Merge "Add log to explain why freezer is not supported" into udc-dev
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 81a3479..1b5795f 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -82,14 +82,6 @@
]
},
{
- "name": "TestablesTests",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- },
- {
"name": "FrameworksCoreTests",
"options": [
{
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 2f6b689..805dfaf 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -2344,11 +2344,7 @@
// UIDTs
if (networkRequest == null) {
throw new IllegalArgumentException(
- "A user-initaited data transfer job must specify a valid network type");
- }
- if (backoffPolicy == BACKOFF_POLICY_LINEAR) {
- throw new IllegalArgumentException(
- "A user-initiated data transfer job cannot have a linear backoff policy.");
+ "A user-initiated data transfer job must specify a valid network type");
}
}
}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index 2ab4324..f48e078 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -166,7 +166,8 @@
* the job in the {@link #onStartJob(JobParameters)} callback.
* @param wantsReschedule {@code true} if this job should be rescheduled according
* to the back-off criteria specified when it was first scheduled; {@code false}
- * otherwise.
+ * otherwise. When {@code false} is returned for a periodic job,
+ * the job will be rescheduled according to its periodic policy.
*/
public final void jobFinished(JobParameters params, boolean wantsReschedule) {
mEngine.jobFinished(params, wantsReschedule);
@@ -217,7 +218,7 @@
* {@link android.app.job.JobInfo.Builder#setRequiredNetworkType(int)}, yet while your
* job was executing the user toggled WiFi. Another example is if you had specified
* {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left
- * its idle maintenance window. There are many other reasons a job can be stopped early besides
+ * its idle state. There are many other reasons a job can be stopped early besides
* constraints no longer being satisfied. {@link JobParameters#getStopReason()} will return the
* reason this method was called. You are solely responsible for the behavior of your
* application upon receipt of this message; your app will likely start to misbehave if you
@@ -241,7 +242,8 @@
* included.
* @return {@code true} to indicate to the JobManager whether you'd like to reschedule
* this job based on the retry criteria provided at job creation-time; or {@code false}
- * to end the job entirely. Regardless of the value returned, your job must stop executing.
+ * to end the job entirely (or, for a periodic job, to reschedule it according to its
+ * requested periodic criteria). Regardless of the value returned, your job must stop executing.
*/
public abstract boolean onStopJob(JobParameters params);
@@ -424,11 +426,14 @@
* 10 seconds after {@link #onStartJob(JobParameters)} is called,
* the system will trigger an ANR and stop this job.
*
+ * The notification must provide an accurate description of the work that the job is doing
+ * and, if possible, the state of the work.
+ *
* <p>
* Note that certain types of jobs
- * (e.g. {@link JobInfo.Builder#setDataTransfer data transfer jobs}) may require the
- * notification to have certain characteristics and their documentation will state
- * any such requirements.
+ * (e.g. {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long) data transfer jobs})
+ * may require the notification to have certain characteristics
+ * and their documentation will state any such requirements.
*
* <p>
* JobScheduler will not remember this notification after the job has finished running,
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 ea14640..d94993d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -482,6 +482,7 @@
case Constants.KEY_RUNTIME_UI_LIMIT_MS:
case Constants.KEY_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR:
case Constants.KEY_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS:
+ case Constants.KEY_RUNTIME_CUMULATIVE_UI_LIMIT_MS:
case Constants.KEY_RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS:
if (!runtimeUpdated) {
mConstants.updateRuntimeConstantsLocked();
@@ -582,6 +583,8 @@
"runtime_min_ui_data_transfer_guarantee_buffer_factor";
private static final String KEY_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS =
"runtime_min_ui_data_transfer_guarantee_ms";
+ private static final String KEY_RUNTIME_CUMULATIVE_UI_LIMIT_MS =
+ "runtime_cumulative_ui_limit_ms";
private static final String KEY_RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS =
"runtime_use_data_estimates_for_limits";
@@ -622,6 +625,7 @@
1.35f;
public static final long DEFAULT_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS =
Math.max(10 * MINUTE_IN_MILLIS, DEFAULT_RUNTIME_MIN_UI_GUARANTEE_MS);
+ public static final long DEFAULT_RUNTIME_CUMULATIVE_UI_LIMIT_MS = 24 * HOUR_IN_MILLIS;
public static final boolean DEFAULT_RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS = false;
static final boolean DEFAULT_PERSIST_IN_SPLIT_FILES = true;
static final int DEFAULT_MAX_NUM_PERSISTED_JOB_WORK_ITEMS = 100_000;
@@ -760,6 +764,12 @@
DEFAULT_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS;
/**
+ * The maximum amount of cumulative time we will let a user-initiated job run for
+ * before downgrading it.
+ */
+ public long RUNTIME_CUMULATIVE_UI_LIMIT_MS = DEFAULT_RUNTIME_CUMULATIVE_UI_LIMIT_MS;
+
+ /**
* Whether to use data estimates to determine execution limits for execution limits.
*/
public boolean RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS =
@@ -881,6 +891,7 @@
KEY_RUNTIME_MIN_UI_GUARANTEE_MS,
KEY_RUNTIME_UI_LIMIT_MS,
KEY_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS,
+ KEY_RUNTIME_CUMULATIVE_UI_LIMIT_MS,
KEY_RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS);
// Make sure min runtime for regular jobs is at least 10 minutes.
@@ -915,6 +926,11 @@
properties.getLong(
KEY_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS,
DEFAULT_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS));
+ // The cumulative runtime limit should be at least the max execution limit.
+ RUNTIME_CUMULATIVE_UI_LIMIT_MS = Math.max(RUNTIME_UI_LIMIT_MS,
+ properties.getLong(
+ KEY_RUNTIME_CUMULATIVE_UI_LIMIT_MS,
+ DEFAULT_RUNTIME_CUMULATIVE_UI_LIMIT_MS));
RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS = properties.getBoolean(
KEY_RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS,
@@ -972,6 +988,7 @@
RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_BUFFER_FACTOR).println();
pw.print(KEY_RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS,
RUNTIME_MIN_UI_DATA_TRANSFER_GUARANTEE_MS).println();
+ pw.print(KEY_RUNTIME_CUMULATIVE_UI_LIMIT_MS, RUNTIME_CUMULATIVE_UI_LIMIT_MS).println();
pw.print(KEY_RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS,
RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS).println();
@@ -2452,11 +2469,16 @@
JobStatus newJob = new JobStatus(failureToReschedule,
elapsedNowMillis + delayMillis,
JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops,
- failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis());
+ failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis(),
+ failureToReschedule.getCumulativeExecutionTimeMs());
if (stopReason == JobParameters.STOP_REASON_USER) {
// Demote all jobs to regular for user stops so they don't keep privileges.
newJob.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
}
+ if (newJob.getCumulativeExecutionTimeMs() >= mConstants.RUNTIME_CUMULATIVE_UI_LIMIT_MS
+ && newJob.shouldTreatAsUserInitiatedJob()) {
+ newJob.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ);
+ }
if (job.isPeriodic()) {
newJob.setOriginalLatestRunTimeElapsed(
failureToReschedule.getOriginalLatestRunTimeElapsed());
@@ -2548,7 +2570,8 @@
elapsedNow + period - flex, elapsedNow + period,
0 /* numFailures */, 0 /* numSystemStops */,
sSystemClock.millis() /* lastSuccessfulRunTime */,
- periodicToReschedule.getLastFailedRunTime());
+ periodicToReschedule.getLastFailedRunTime(),
+ 0 /* Reset cumulativeExecutionTime because of successful execution */);
}
final long newEarliestRunTimeElapsed = newLatestRuntimeElapsed
@@ -2563,7 +2586,8 @@
newEarliestRunTimeElapsed, newLatestRuntimeElapsed,
0 /* numFailures */, 0 /* numSystemStops */,
sSystemClock.millis() /* lastSuccessfulRunTime */,
- periodicToReschedule.getLastFailedRunTime());
+ periodicToReschedule.getLastFailedRunTime(),
+ 0 /* Reset cumulativeExecutionTime because of successful execution */);
}
// JobCompletedListener implementations.
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 f3203ca..b080bf3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -106,6 +106,7 @@
private static final long OP_TIMEOUT_MILLIS = 8 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/** Amount of time the JobScheduler will wait for a job to provide a required notification. */
private static final long NOTIFICATION_TIMEOUT_MILLIS = 10_000L * Build.HW_TIMEOUT_MULTIPLIER;
+ private static final long EXECUTION_DURATION_STAMP_PERIOD_MILLIS = 5 * 60_000L;
private static final String[] VERB_STRINGS = {
"VERB_BINDING", "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_FINISHED"
@@ -191,6 +192,8 @@
private long mMaxExecutionTimeMillis;
/** Whether this job is required to provide a notification and we're still waiting for it. */
private boolean mAwaitingNotification;
+ /** The last time we updated the job's execution duration, in the elapsed realtime timebase. */
+ private long mLastExecutionDurationStampTimeElapsed;
private long mEstimatedDownloadBytes;
private long mEstimatedUploadBytes;
@@ -1245,7 +1248,15 @@
/* anrMessage */ "required notification not provided",
/* triggerAnr */ true);
} else {
- Slog.e(TAG, "Unexpected op timeout while EXECUTING");
+ final long timeSinceDurationStampTimeMs =
+ nowElapsed - mLastExecutionDurationStampTimeElapsed;
+ if (timeSinceDurationStampTimeMs < EXECUTION_DURATION_STAMP_PERIOD_MILLIS) {
+ Slog.e(TAG, "Unexpected op timeout while EXECUTING");
+ }
+ // Update the execution time even if this wasn't the pre-set time.
+ mRunningJob.incrementCumulativeExecutionTime(timeSinceDurationStampTimeMs);
+ mService.mJobs.touchJob(mRunningJob);
+ mLastExecutionDurationStampTimeElapsed = nowElapsed;
scheduleOpTimeOutLocked();
}
break;
@@ -1314,8 +1325,11 @@
Slog.d(TAG, "Cleaning up " + mRunningJob.toShortString()
+ " reschedule=" + reschedule + " reason=" + loggingDebugReason);
}
+ final long nowElapsed = sElapsedRealtimeClock.millis();
applyStoppedReasonLocked(loggingDebugReason);
completedJob = mRunningJob;
+ completedJob.incrementCumulativeExecutionTime(
+ nowElapsed - mLastExecutionDurationStampTimeElapsed);
// Use the JobParameters stop reasons for logging and metric purposes,
// but if the job was marked for death, use that reason for rescheduling purposes.
// The discrepancy could happen if a job ends up stopping for some reason
@@ -1342,7 +1356,7 @@
mPreviousJobHadSuccessfulFinish =
(loggingInternalStopReason == JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
if (!mPreviousJobHadSuccessfulFinish) {
- mLastUnsuccessfulFinishElapsed = sElapsedRealtimeClock.millis();
+ mLastUnsuccessfulFinishElapsed = nowElapsed;
}
mJobPackageTracker.noteInactive(completedJob,
loggingInternalStopReason, loggingDebugReason);
@@ -1411,6 +1425,7 @@
mDeathMarkStopReason = JobParameters.STOP_REASON_UNDEFINED;
mDeathMarkInternalStopReason = 0;
mDeathMarkDebugReason = null;
+ mLastExecutionDurationStampTimeElapsed = 0;
mPendingStopReason = JobParameters.STOP_REASON_UNDEFINED;
mPendingInternalStopReason = 0;
mPendingDebugStopReason = null;
@@ -1460,6 +1475,7 @@
if (mAwaitingNotification) {
minTimeout = Math.min(minTimeout, NOTIFICATION_TIMEOUT_MILLIS);
}
+ minTimeout = Math.min(minTimeout, EXECUTION_DURATION_STAMP_PERIOD_MILLIS);
timeoutMillis = minTimeout;
break;
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 a96a4ef..c540517 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -236,7 +236,8 @@
convertRtcBoundsToElapsed(utcTimes, elapsedNow);
JobStatus newJob = new JobStatus(job,
elapsedRuntimes.first, elapsedRuntimes.second,
- 0, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime());
+ 0, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime(),
+ job.getCumulativeExecutionTimeMs());
newJob.prepareLocked();
toAdd.add(newJob);
toRemove.add(job);
@@ -786,7 +787,7 @@
* Write out a tag with data comprising the required fields and bias of this job and
* its client.
*/
- private void addAttributesToJobTag(XmlSerializer out, JobStatus jobStatus)
+ private void addAttributesToJobTag(TypedXmlSerializer out, JobStatus jobStatus)
throws IOException {
out.attribute(null, "jobid", Integer.toString(jobStatus.getJobId()));
out.attribute(null, "package", jobStatus.getServiceComponent().getPackageName());
@@ -813,6 +814,9 @@
String.valueOf(jobStatus.getLastSuccessfulRunTime()));
out.attribute(null, "lastFailedRunTime",
String.valueOf(jobStatus.getLastFailedRunTime()));
+
+ out.attributeLong(null, "cumulativeExecutionTime",
+ jobStatus.getCumulativeExecutionTimeMs());
}
private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
@@ -1190,6 +1194,7 @@
int uid, sourceUserId;
long lastSuccessfulRunTime;
long lastFailedRunTime;
+ long cumulativeExecutionTime;
int internalFlags = 0;
// Read out job identifier attributes and bias.
@@ -1230,6 +1235,9 @@
val = parser.getAttributeValue(null, "lastFailedRunTime");
lastFailedRunTime = val == null ? 0 : Long.parseLong(val);
+
+ cumulativeExecutionTime =
+ parser.getAttributeLong(null, "cumulativeExecutionTime", 0);
} catch (NumberFormatException e) {
Slog.e(TAG, "Error parsing job's required fields, skipping");
return null;
@@ -1402,7 +1410,7 @@
builtJob, uid, sourcePackageName, sourceUserId,
appBucket, namespace, sourceTag,
elapsedRuntimes.first, elapsedRuntimes.second,
- lastSuccessfulRunTime, lastFailedRunTime,
+ lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTime,
(rtcIsGood) ? null : rtcRuntimes, internalFlags, /* dynamicConstraints */ 0);
if (jobWorkItems != null) {
for (int i = 0; i < jobWorkItems.size(); ++i) {
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 17dde90..26d6ba2 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
@@ -375,6 +375,11 @@
* and is thus considered demoted from whatever privileged state it had in the past.
*/
public static final int INTERNAL_FLAG_DEMOTED_BY_USER = 1 << 1;
+ /**
+ * Flag for {@link #mInternalFlags}: this job is demoted by the system
+ * from running as a user-initiated job.
+ */
+ public static final int INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ = 1 << 2;
/** Minimum difference between start and end time to have flexible constraint */
@VisibleForTesting
@@ -385,6 +390,12 @@
*/
private int mInternalFlags;
+ /**
+ * The cumulative amount of time this job has run for, including previous executions.
+ * This is reset for periodic jobs upon a successful job execution.
+ */
+ private long mCumulativeExecutionTimeMs;
+
// These are filled in by controllers when preparing for execution.
public ArraySet<Uri> changedUris;
public ArraySet<String> changedAuthorities;
@@ -550,7 +561,8 @@
int sourceUserId, int standbyBucket, @Nullable String namespace, String tag,
int numFailures, int numSystemStops,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
- long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags,
+ long lastSuccessfulRunTime, long lastFailedRunTime, long cumulativeExecutionTimeMs,
+ int internalFlags,
int dynamicConstraints) {
this.job = job;
this.callingUid = callingUid;
@@ -650,6 +662,8 @@
mReadyDynamicSatisfied = false;
}
+ mCumulativeExecutionTimeMs = cumulativeExecutionTimeMs;
+
mLastSuccessfulRunTime = lastSuccessfulRunTime;
mLastFailedRunTime = lastFailedRunTime;
@@ -684,6 +698,7 @@
jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getNumSystemStops(),
jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
+ jobStatus.getCumulativeExecutionTimeMs(),
jobStatus.getInternalFlags(), jobStatus.mDynamicConstraints);
mPersistedUtcTimes = jobStatus.mPersistedUtcTimes;
if (jobStatus.mPersistedUtcTimes != null) {
@@ -711,13 +726,15 @@
int standbyBucket, @Nullable String namespace, String sourceTag,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime,
+ long cumulativeExecutionTimeMs,
Pair<Long, Long> persistedExecutionTimesUTC,
int innerFlags, int dynamicConstraints) {
this(job, callingUid, sourcePkgName, sourceUserId,
standbyBucket, namespace,
sourceTag, /* numFailures */ 0, /* numSystemStops */ 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
- lastSuccessfulRunTime, lastFailedRunTime, innerFlags, dynamicConstraints);
+ lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs,
+ innerFlags, dynamicConstraints);
// Only during initial inflation do we record the UTC-timebase execution bounds
// read from the persistent store. If we ever have to recreate the JobStatus on
@@ -735,14 +752,16 @@
public JobStatus(JobStatus rescheduling,
long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int numFailures, int numSystemStops,
- long lastSuccessfulRunTime, long lastFailedRunTime) {
+ long lastSuccessfulRunTime, long lastFailedRunTime,
+ long cumulativeExecutionTimeMs) {
this(rescheduling.job, rescheduling.getUid(),
rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
rescheduling.getStandbyBucket(), rescheduling.getNamespace(),
rescheduling.getSourceTag(), numFailures, numSystemStops,
newEarliestRuntimeElapsedMillis,
newLatestRuntimeElapsedMillis,
- lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags(),
+ lastSuccessfulRunTime, lastFailedRunTime, cumulativeExecutionTimeMs,
+ rescheduling.getInternalFlags(),
rescheduling.mDynamicConstraints);
}
@@ -780,6 +799,7 @@
standbyBucket, namespace, tag, /* numFailures */ 0, /* numSystemStops */ 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
+ /* cumulativeExecutionTime */ 0,
/*innerFlags=*/ 0, /* dynamicConstraints */ 0);
}
@@ -1312,6 +1332,14 @@
return job.isPersisted();
}
+ public long getCumulativeExecutionTimeMs() {
+ return mCumulativeExecutionTimeMs;
+ }
+
+ public void incrementCumulativeExecutionTime(long incrementMs) {
+ mCumulativeExecutionTimeMs += incrementMs;
+ }
+
public long getEarliestRunTime() {
return earliestRunTimeElapsedMillis;
}
@@ -1405,7 +1433,8 @@
*/
public boolean shouldTreatAsUserInitiatedJob() {
return getJob().isUserInitiated()
- && (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_USER) == 0;
+ && (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_USER) == 0
+ && (getInternalFlags() & INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ) == 0;
}
/**
@@ -2124,9 +2153,9 @@
sb.append(" READY");
} else {
sb.append(" satisfied:0x").append(Integer.toHexString(satisfiedConstraints));
+ final int requiredConstraints = mRequiredConstraintsOfInterest | IMPLICIT_CONSTRAINTS;
sb.append(" unsatisfied:0x").append(Integer.toHexString(
- (satisfiedConstraints & (mRequiredConstraintsOfInterest | IMPLICIT_CONSTRAINTS))
- ^ mRequiredConstraintsOfInterest));
+ (satisfiedConstraints & requiredConstraints) ^ requiredConstraints));
}
sb.append("}");
return sb.toString();
@@ -2655,6 +2684,11 @@
pw.print(", original latest=");
formatRunTime(pw, mOriginalLatestRunTimeElapsedMillis, NO_LATEST_RUNTIME, nowElapsed);
pw.println();
+ if (mCumulativeExecutionTimeMs != 0) {
+ pw.print("Cumulative execution time=");
+ TimeUtils.formatDuration(mCumulativeExecutionTimeMs, pw);
+ pw.println();
+ }
if (numFailures != 0) {
pw.print("Num failures: "); pw.println(numFailures);
}
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 4d8b3e1..d2150b8 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -182,7 +182,7 @@
if (mIrs.isPackageExempted(userId, pkgName)) {
return mMinSatiatedBalanceExempted;
}
- if (mIrs.isHeadlessSystemApp(pkgName)) {
+ if (mIrs.isHeadlessSystemApp(userId, pkgName)) {
return mMinSatiatedBalanceHeadlessSystemApp;
}
// TODO: take other exemptions into account
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
index dffed0f..49c6d1b 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
@@ -22,6 +22,7 @@
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.Context;
+import android.content.Intent;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
@@ -35,9 +36,23 @@
class InstalledPackageInfo {
static final int NO_UID = -1;
+ /**
+ * Flags to use when querying for front door activities. Disabled components are included
+ * are included for completeness since the app can enable them at any time.
+ */
+ private static final int HEADLESS_APP_QUERY_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DISABLED_COMPONENTS;
+
public final int uid;
public final String packageName;
public final boolean hasCode;
+ /**
+ * Whether the app is a system app that is "headless." Headless in this context means that
+ * the app doesn't have any "front door" activities --- activities that would show in the
+ * launcher.
+ */
+ public final boolean isHeadlessSystemApp;
public final boolean isSystemInstaller;
@Nullable
public final String installerPackageName;
@@ -48,6 +63,17 @@
uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
packageName = packageInfo.packageName;
hasCode = applicationInfo != null && applicationInfo.hasCode();
+
+ final PackageManager packageManager = context.getPackageManager();
+ final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(packageName);
+ isHeadlessSystemApp = applicationInfo != null
+ && (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp())
+ && ArrayUtils.isEmpty(
+ packageManager.queryIntentActivitiesAsUser(
+ frontDoorActivityIntent, HEADLESS_APP_QUERY_FLAGS, userId));
+
isSystemInstaller = applicationInfo != null
&& ArrayUtils.indexOf(
packageInfo.requestedPermissions, Manifest.permission.INSTALL_PACKAGES) >= 0
@@ -65,4 +91,16 @@
installerPackageName =
installSourceInfo == null ? null : installSourceInfo.getInstallingPackageName();
}
+
+ @Override
+ public String toString() {
+ return "IPO{"
+ + "uid=" + uid
+ + ", pkgName=" + packageName
+ + (hasCode ? " HAS_CODE" : "")
+ + (isHeadlessSystemApp ? " HEADLESS_SYSTEM" : "")
+ + (isSystemInstaller ? " SYSTEM_INSTALLER" : "")
+ + ", installer=" + installerPackageName
+ + '}';
+ }
}
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 1c915bc..7f6a75e 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -501,12 +501,16 @@
}
}
- boolean isHeadlessSystemApp(@NonNull String pkgName) {
+ boolean isHeadlessSystemApp(final int userId, @NonNull String pkgName) {
if (pkgName == null) {
Slog.wtfStack(TAG, "isHeadlessSystemApp called with null package");
return false;
}
synchronized (mLock) {
+ final InstalledPackageInfo ipo = getInstalledPackageInfo(userId, pkgName);
+ if (ipo != null && ipo.isHeadlessSystemApp) {
+ return true;
+ }
// The wellbeing app is pre-set on the device, not expected to be interacted with
// much by the user, but can be expected to do work in the background on behalf of
// the user. As such, it's a pseudo-headless system app, so treat it as a headless
@@ -1754,6 +1758,10 @@
pw.print("Exempted apps", mExemptedApps);
pw.println();
+ pw.println();
+ pw.print("Wellbeing app=");
+ pw.println(mWellbeingPackage == null ? "None" : mWellbeingPackage);
+
boolean printedVips = false;
pw.println();
pw.print("VIPs:");
@@ -1832,6 +1840,37 @@
pw.println();
mAnalyst.dump(pw);
+
+ // Put this at the end since this may be a lot and we want to have the earlier
+ // information easily accessible.
+ boolean printedInterestingIpos = false;
+ pw.println();
+ pw.print("Interesting apps:");
+ pw.increaseIndent();
+ for (int u = 0; u < mPkgCache.numMaps(); ++u) {
+ for (int p = 0; p < mPkgCache.numElementsForKeyAt(u); ++p) {
+ final InstalledPackageInfo ipo = mPkgCache.valueAt(u, p);
+
+ // Printing out every single app will be too much. Only print apps that
+ // have some interesting characteristic.
+ final boolean isInteresting = ipo.hasCode
+ && ipo.isHeadlessSystemApp
+ && !UserHandle.isCore(ipo.uid);
+ if (!isInteresting) {
+ continue;
+ }
+
+ printedInterestingIpos = true;
+ pw.println();
+ pw.print(ipo);
+ }
+ }
+ if (printedInterestingIpos) {
+ pw.println();
+ } else {
+ pw.print(" None");
+ }
+ pw.decreaseIndent();
}
}
}
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 526e876..91a291f 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -197,7 +197,7 @@
final long baseBalance;
if (mIrs.isPackageExempted(userId, pkgName)) {
baseBalance = mMinSatiatedBalanceExempted;
- } else if (mIrs.isHeadlessSystemApp(pkgName)) {
+ } else if (mIrs.isHeadlessSystemApp(userId, pkgName)) {
baseBalance = mMinSatiatedBalanceHeadlessSystemApp;
} else {
baseBalance = mMinSatiatedBalanceOther;
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6177a9f..3fbd3b8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3263,6 +3263,7 @@
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setVirtualSensorCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensorCallback);
+ method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setVirtualSensorDirectChannelCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensorDirectChannelCallback);
}
}
@@ -3326,16 +3327,18 @@
public interface VirtualSensorCallback {
method public void onConfigurationChanged(@NonNull android.companion.virtual.sensor.VirtualSensor, boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
- method public default void onDirectChannelConfigured(@IntRange(from=1) int, @NonNull android.companion.virtual.sensor.VirtualSensor, int, @IntRange(from=1) int);
- method public default void onDirectChannelCreated(@IntRange(from=1) int, @NonNull android.os.SharedMemory);
- method public default void onDirectChannelDestroyed(@IntRange(from=1) int);
}
public final class VirtualSensorConfig implements android.os.Parcelable {
method public int describeContents();
method public int getDirectChannelTypesSupported();
method public int getHighestDirectReportRateLevel();
+ method public int getMaxDelay();
+ method public float getMaximumRange();
+ method public int getMinDelay();
method @NonNull public String getName();
+ method public float getPower();
+ method public float getResolution();
method public int getType();
method @Nullable public String getVendor();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -3347,9 +3350,29 @@
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setDirectChannelTypesSupported(int);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setHighestDirectReportRateLevel(int);
+ method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setMaxDelay(int);
+ method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setMaximumRange(float);
+ method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setMinDelay(int);
+ method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setPower(float);
+ method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setResolution(float);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
}
+ public interface VirtualSensorDirectChannelCallback {
+ method public void onDirectChannelConfigured(@IntRange(from=1) int, @NonNull android.companion.virtual.sensor.VirtualSensor, int, @IntRange(from=1) int);
+ method public void onDirectChannelCreated(@IntRange(from=1) int, @NonNull android.os.SharedMemory);
+ method public void onDirectChannelDestroyed(@IntRange(from=1) int);
+ }
+
+ public final class VirtualSensorDirectChannelWriter implements java.lang.AutoCloseable {
+ ctor public VirtualSensorDirectChannelWriter();
+ method public void addChannel(@IntRange(from=1) int, @NonNull android.os.SharedMemory) throws android.system.ErrnoException;
+ method public void close();
+ method public boolean configureChannel(@IntRange(from=1) int, @NonNull android.companion.virtual.sensor.VirtualSensor, int, @IntRange(from=1) int);
+ method public void removeChannel(@IntRange(from=1) int);
+ method public boolean writeSensorEvent(@NonNull android.companion.virtual.sensor.VirtualSensor, @NonNull android.companion.virtual.sensor.VirtualSensorEvent);
+ }
+
public final class VirtualSensorEvent implements android.os.Parcelable {
method public int describeContents();
method public long getTimestampNanos();
@@ -4957,6 +4980,7 @@
public final class VirtualKeyEvent implements android.os.Parcelable {
method public int describeContents();
method public int getAction();
+ method public long getEventTimeNanos();
method public int getKeyCode();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int ACTION_DOWN = 0; // 0x0
@@ -4968,6 +4992,7 @@
ctor public VirtualKeyEvent.Builder();
method @NonNull public android.hardware.input.VirtualKeyEvent build();
method @NonNull public android.hardware.input.VirtualKeyEvent.Builder setAction(int);
+ method @NonNull public android.hardware.input.VirtualKeyEvent.Builder setEventTimeNanos(long);
method @NonNull public android.hardware.input.VirtualKeyEvent.Builder setKeyCode(int);
}
@@ -5005,6 +5030,7 @@
method public int describeContents();
method public int getAction();
method public int getButtonCode();
+ method public long getEventTimeNanos();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int ACTION_BUTTON_PRESS = 11; // 0xb
field public static final int ACTION_BUTTON_RELEASE = 12; // 0xc
@@ -5021,6 +5047,7 @@
method @NonNull public android.hardware.input.VirtualMouseButtonEvent build();
method @NonNull public android.hardware.input.VirtualMouseButtonEvent.Builder setAction(int);
method @NonNull public android.hardware.input.VirtualMouseButtonEvent.Builder setButtonCode(int);
+ method @NonNull public android.hardware.input.VirtualMouseButtonEvent.Builder setEventTimeNanos(long);
}
public final class VirtualMouseConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
@@ -5036,6 +5063,7 @@
public final class VirtualMouseRelativeEvent implements android.os.Parcelable {
method public int describeContents();
+ method public long getEventTimeNanos();
method public float getRelativeX();
method public float getRelativeY();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -5045,12 +5073,14 @@
public static final class VirtualMouseRelativeEvent.Builder {
ctor public VirtualMouseRelativeEvent.Builder();
method @NonNull public android.hardware.input.VirtualMouseRelativeEvent build();
+ method @NonNull public android.hardware.input.VirtualMouseRelativeEvent.Builder setEventTimeNanos(long);
method @NonNull public android.hardware.input.VirtualMouseRelativeEvent.Builder setRelativeX(float);
method @NonNull public android.hardware.input.VirtualMouseRelativeEvent.Builder setRelativeY(float);
}
public final class VirtualMouseScrollEvent implements android.os.Parcelable {
method public int describeContents();
+ method public long getEventTimeNanos();
method public float getXAxisMovement();
method public float getYAxisMovement();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -5060,6 +5090,7 @@
public static final class VirtualMouseScrollEvent.Builder {
ctor public VirtualMouseScrollEvent.Builder();
method @NonNull public android.hardware.input.VirtualMouseScrollEvent build();
+ method @NonNull public android.hardware.input.VirtualMouseScrollEvent.Builder setEventTimeNanos(long);
method @NonNull public android.hardware.input.VirtualMouseScrollEvent.Builder setXAxisMovement(@FloatRange(from=-1.0F, to=1.0f) float);
method @NonNull public android.hardware.input.VirtualMouseScrollEvent.Builder setYAxisMovement(@FloatRange(from=-1.0F, to=1.0f) float);
}
@@ -5085,6 +5116,7 @@
public final class VirtualTouchEvent implements android.os.Parcelable {
method public int describeContents();
method public int getAction();
+ method public long getEventTimeNanos();
method public float getMajorAxisSize();
method public int getPointerId();
method public float getPressure();
@@ -5105,6 +5137,7 @@
ctor public VirtualTouchEvent.Builder();
method @NonNull public android.hardware.input.VirtualTouchEvent build();
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setAction(int);
+ method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setEventTimeNanos(long);
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setMajorAxisSize(@FloatRange(from=0.0f) float);
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setPointerId(@IntRange(from=0, to=0x10 - 1) int);
method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setPressure(@FloatRange(from=0.0f) float);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 999075d..0ba56b9 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3052,7 +3052,7 @@
mPM.setComponentEnabledSetting(componentName, enabled
? COMPONENT_ENABLED_STATE_DEFAULT
: COMPONENT_ENABLED_STATE_DISABLED,
- DONT_KILL_APP, getUserId());
+ DONT_KILL_APP, getUserId(), mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3075,7 +3075,8 @@
public void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags) {
try {
- mPM.setComponentEnabledSetting(componentName, newState, flags, getUserId());
+ mPM.setComponentEnabledSetting(componentName, newState, flags, getUserId(),
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3084,7 +3085,7 @@
@Override
public void setComponentEnabledSettings(List<ComponentEnabledSetting> settings) {
try {
- mPM.setComponentEnabledSettings(settings, getUserId());
+ mPM.setComponentEnabledSettings(settings, getUserId(), mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0cd42a3..82f4315 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3619,6 +3619,17 @@
scheduleFinalCleanup(getClass().getName(), getOuterContext().getClass().getSimpleName());
}
+ @Override
+ public void closeSystemDialogs() {
+ final Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ final Bundle options = BroadcastOptions.makeBasic()
+ .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
+ .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
+ .toBundle();
+ sendBroadcast(intent, null /* receiverPermission */, options);
+ }
+
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 403acad..97d4562 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -108,6 +108,15 @@
int getUidProcessState(int uid, in String callingPackage);
@UnsupportedAppUsage
int checkPermission(in String permission, int pid, int uid);
+
+ /** Logs start of an API call to associate with an FGS, used for FGS Type Metrics */
+ void logFgsApiBegin(int apiType, int appUid, int appPid);
+
+ /** Logs stop of an API call to associate with an FGS, used for FGS Type Metrics */
+ void logFgsApiEnd(int apiType, int appUid, int appPid);
+
+ /** Logs API state change to associate with an FGS, used for FGS Type Metrics */
+ void logFgsApiStateChanged(int apiType, int state, int appUid, int appPid);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
@@ -870,16 +879,6 @@
/** Returns if the service is a short-service is still "alive" and past the timeout. */
boolean shouldServiceTimeOut(in ComponentName className, in IBinder token);
- /** Logs start of an API call to associate with an FGS, used for FGS Type Metrics */
- void logFgsApiBegin(int apiType, int appUid, int appPid);
-
- /** Logs stop of an API call to associate with an FGS, used for FGS Type Metrics */
- void logFgsApiEnd(int apiType, int appUid, int appPid);
-
- /** Logs API state change to associate with an FGS, used for FGS Type Metrics */
- void logFgsApiStateChanged(int apiType, int state, int appUid, int appPid);
-
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
void registerUidFrozenStateChangedCallback(in IUidFrozenStateChangedCallback callback);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
void unregisterUidFrozenStateChangedCallback(in IUidFrozenStateChangedCallback callback);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 4dc7253..c131ce5 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -28,6 +28,7 @@
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.input.InputManager;
+import android.hardware.input.InputManagerGlobal;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -1130,7 +1131,7 @@
newEvent.setFlags(event.getFlags() | KeyEvent.FLAG_FROM_SYSTEM);
setDisplayIfNeeded(newEvent);
- InputManager.getInstance().injectInputEvent(newEvent,
+ InputManagerGlobal.getInstance().injectInputEvent(newEvent,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
@@ -1229,7 +1230,7 @@
}
// Direct the injected event into windows owned by the instrumentation target.
- InputManager.getInstance().injectInputEvent(
+ InputManagerGlobal.getInstance().injectInputEvent(
event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH, Process.myUid());
if (syncAfter) {
@@ -1259,7 +1260,7 @@
if (!event.isFromSource(InputDevice.SOURCE_CLASS_TRACKBALL)) {
event.setSource(InputDevice.SOURCE_TRACKBALL);
}
- InputManager.getInstance().injectInputEvent(event,
+ InputManagerGlobal.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cc9c329..7aedd30 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5286,7 +5286,7 @@
boolean hasSecondLine = showProgress;
if (p.hasTitle()) {
contentView.setViewVisibility(p.mTitleViewId, View.VISIBLE);
- contentView.setTextViewText(p.mTitleViewId, processTextSpans(p.mTitle));
+ contentView.setTextViewText(p.mTitleViewId, ensureColorSpanContrast(p.mTitle, p));
setTextViewColorPrimary(contentView, p.mTitleViewId, p);
} else if (p.mTitleViewId != R.id.title) {
// This alternate title view ID is not cleared by resetStandardTemplate
@@ -5296,7 +5296,7 @@
if (p.mText != null && p.mText.length() != 0
&& (!showProgress || p.mAllowTextWithProgress)) {
contentView.setViewVisibility(p.mTextViewId, View.VISIBLE);
- contentView.setTextViewText(p.mTextViewId, processTextSpans(p.mText));
+ contentView.setTextViewText(p.mTextViewId, ensureColorSpanContrast(p.mText, p));
setTextViewColorSecondary(contentView, p.mTextViewId, p);
hasSecondLine = true;
} else if (p.mTextViewId != R.id.text) {
@@ -5323,13 +5323,6 @@
RemoteViews.MARGIN_BOTTOM, marginDimen);
}
- private CharSequence processTextSpans(CharSequence text) {
- if (mInNightMode) {
- return ContrastColorUtil.clearColorSpans(text);
- }
- return text;
- }
-
private void setTextViewColorPrimary(RemoteViews contentView, @IdRes int id,
StandardTemplateParams p) {
contentView.setTextColor(id, getPrimaryTextColor(p));
@@ -5581,9 +5574,8 @@
headerText = mN.extras.getCharSequence(EXTRA_INFO_TEXT);
}
if (!TextUtils.isEmpty(headerText)) {
- // TODO: Remove the span entirely to only have the string with propper formating.
- contentView.setTextViewText(R.id.header_text, processTextSpans(
- processLegacyText(headerText)));
+ contentView.setTextViewText(R.id.header_text, ensureColorSpanContrast(
+ processLegacyText(headerText), p));
setTextViewColorSecondary(contentView, R.id.header_text, p);
contentView.setViewVisibility(R.id.header_text, View.VISIBLE);
if (hasTextToLeft) {
@@ -5604,8 +5596,8 @@
return false;
}
if (!TextUtils.isEmpty(p.mHeaderTextSecondary)) {
- contentView.setTextViewText(R.id.header_text_secondary, processTextSpans(
- processLegacyText(p.mHeaderTextSecondary)));
+ contentView.setTextViewText(R.id.header_text_secondary, ensureColorSpanContrast(
+ processLegacyText(p.mHeaderTextSecondary), p));
setTextViewColorSecondary(contentView, R.id.header_text_secondary, p);
contentView.setViewVisibility(R.id.header_text_secondary, View.VISIBLE);
if (hasTextToLeft) {
@@ -5846,7 +5838,7 @@
big.setViewVisibility(R.id.notification_material_reply_text_1_container,
View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_1,
- processTextSpans(replyText[0].getText()));
+ ensureColorSpanContrast(replyText[0].getText(), p));
setTextViewColorSecondary(big, R.id.notification_material_reply_text_1, p);
big.setViewVisibility(R.id.notification_material_reply_progress,
showSpinner ? View.VISIBLE : View.GONE);
@@ -5858,7 +5850,7 @@
&& p.maxRemoteInputHistory > 1) {
big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_2,
- processTextSpans(replyText[1].getText()));
+ ensureColorSpanContrast(replyText[1].getText(), p));
setTextViewColorSecondary(big, R.id.notification_material_reply_text_2, p);
if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2].getText())
@@ -5866,7 +5858,7 @@
big.setViewVisibility(
R.id.notification_material_reply_text_3, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_3,
- processTextSpans(replyText[2].getText()));
+ ensureColorSpanContrast(replyText[2].getText(), p));
setTextViewColorSecondary(big, R.id.notification_material_reply_text_3, p);
}
}
@@ -6280,9 +6272,9 @@
fullLengthColor, notifBackgroundColor);
}
// Remove full-length color spans and ensure text contrast with the button fill.
- title = ensureColorSpanContrast(title, buttonFillColor);
+ title = ContrastColorUtil.ensureColorSpanContrast(title, buttonFillColor);
}
- button.setTextViewText(R.id.action0, processTextSpans(title));
+ button.setTextViewText(R.id.action0, ensureColorSpanContrast(title, p));
int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
buttonFillColor, mInNightMode);
if (tombstone) {
@@ -6307,8 +6299,8 @@
button.setIntDimen(R.id.action0, "setMinimumWidth", minWidthDimen);
}
} else {
- button.setTextViewText(R.id.action0, processTextSpans(
- processLegacyText(action.title)));
+ button.setTextViewText(R.id.action0, ensureColorSpanContrast(
+ action.title, p));
button.setTextColor(R.id.action0, getStandardActionColor(p));
}
// CallStyle notifications add action buttons which don't actually exist in mActions,
@@ -6385,72 +6377,12 @@
* Ensures contrast on color spans against a background color.
* Note that any full-length color spans will be removed instead of being contrasted.
*
- * @param charSequence the charSequence on which the spans are
- * @param background the background color to ensure the contrast against
- * @return the contrasted charSequence
* @hide
*/
@VisibleForTesting
- public static CharSequence ensureColorSpanContrast(CharSequence charSequence,
- int background) {
- if (charSequence instanceof Spanned) {
- Spanned ss = (Spanned) charSequence;
- Object[] spans = ss.getSpans(0, ss.length(), Object.class);
- SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
- for (Object span : spans) {
- Object resultSpan = span;
- int spanStart = ss.getSpanStart(span);
- int spanEnd = ss.getSpanEnd(span);
- boolean fullLength = (spanEnd - spanStart) == charSequence.length();
- if (resultSpan instanceof CharacterStyle) {
- resultSpan = ((CharacterStyle) span).getUnderlying();
- }
- if (resultSpan instanceof TextAppearanceSpan) {
- TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
- ColorStateList textColor = originalSpan.getTextColor();
- if (textColor != null) {
- if (fullLength) {
- // Let's drop the color from the span
- textColor = null;
- } else {
- int[] colors = textColor.getColors();
- int[] newColors = new int[colors.length];
- for (int i = 0; i < newColors.length; i++) {
- boolean isBgDark = isColorDark(background);
- newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
- colors[i], background, isBgDark);
- }
- textColor = new ColorStateList(textColor.getStates().clone(),
- newColors);
- }
- resultSpan = new TextAppearanceSpan(
- originalSpan.getFamily(),
- originalSpan.getTextStyle(),
- originalSpan.getTextSize(),
- textColor,
- originalSpan.getLinkTextColor());
- }
- } else if (resultSpan instanceof ForegroundColorSpan) {
- if (fullLength) {
- resultSpan = null;
- } else {
- ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
- int foregroundColor = originalSpan.getForegroundColor();
- boolean isBgDark = isColorDark(background);
- foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
- foregroundColor, background, isBgDark);
- resultSpan = new ForegroundColorSpan(foregroundColor);
- }
- } else {
- resultSpan = span;
- }
- if (resultSpan != null) {
- builder.setSpan(resultSpan, spanStart, spanEnd, ss.getSpanFlags(span));
- }
- }
- return builder;
- }
- return charSequence;
+ public CharSequence ensureColorSpanContrast(CharSequence charSequence,
+ StandardTemplateParams p) {
+ return ContrastColorUtil.ensureColorSpanContrast(charSequence, getBackgroundColor(p));
}
/**
@@ -7586,8 +7518,8 @@
RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource(),
p, null /* result */);
if (mSummaryTextSet) {
- contentView.setTextViewText(R.id.text, mBuilder.processTextSpans(
- mBuilder.processLegacyText(mSummaryText)));
+ contentView.setTextViewText(R.id.text, mBuilder.ensureColorSpanContrast(
+ mBuilder.processLegacyText(mSummaryText), p));
mBuilder.setTextViewColorSecondary(contentView, R.id.text, p);
contentView.setViewVisibility(R.id.text, View.VISIBLE);
}
@@ -8207,6 +8139,13 @@
@Override
public void addExtras(Bundle extras) {
super.addExtras(extras);
+ addExtras(extras, false, 0);
+ }
+
+ /**
+ * @hide
+ */
+ public void addExtras(Bundle extras, boolean ensureContrast, int backgroundColor) {
if (mUser != null) {
// For legacy usages
extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUser.getName());
@@ -8215,11 +8154,13 @@
if (mConversationTitle != null) {
extras.putCharSequence(EXTRA_CONVERSATION_TITLE, mConversationTitle);
}
- if (!mMessages.isEmpty()) { extras.putParcelableArray(EXTRA_MESSAGES,
- Message.getBundleArrayForMessages(mMessages));
+ if (!mMessages.isEmpty()) {
+ extras.putParcelableArray(EXTRA_MESSAGES,
+ getBundleArrayForMessages(mMessages, ensureContrast, backgroundColor));
}
- if (!mHistoricMessages.isEmpty()) { extras.putParcelableArray(EXTRA_HISTORIC_MESSAGES,
- Message.getBundleArrayForMessages(mHistoricMessages));
+ if (!mHistoricMessages.isEmpty()) {
+ extras.putParcelableArray(EXTRA_HISTORIC_MESSAGES, getBundleArrayForMessages(
+ mHistoricMessages, ensureContrast, backgroundColor));
}
if (mShortcutIcon != null) {
extras.putParcelable(EXTRA_CONVERSATION_ICON, mShortcutIcon);
@@ -8230,6 +8171,20 @@
extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, mIsGroupConversation);
}
+ private static Bundle[] getBundleArrayForMessages(List<Message> messages,
+ boolean ensureContrast, int backgroundColor) {
+ Bundle[] bundles = new Bundle[messages.size()];
+ final int N = messages.size();
+ for (int i = 0; i < N; i++) {
+ final Message m = messages.get(i);
+ if (ensureContrast) {
+ m.ensureColorContrast(backgroundColor);
+ }
+ bundles[i] = m.toBundle();
+ }
+ return bundles;
+ }
+
private void fixTitleAndTextExtras(Bundle extras) {
Message m = findLatestIncomingMessage();
CharSequence text = (m == null) ? null : m.mText;
@@ -8441,7 +8396,7 @@
mBuilder.setTextViewColorSecondary(contentView, R.id.app_name_divider, p);
}
- addExtras(mBuilder.mN.extras);
+ addExtras(mBuilder.mN.extras, true, mBuilder.getBackgroundColor(p));
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
mBuilder.getSmallIconColor(p));
contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
@@ -8587,7 +8542,7 @@
static final String KEY_EXTRAS_BUNDLE = "extras";
static final String KEY_REMOTE_INPUT_HISTORY = "remote_input_history";
- private final CharSequence mText;
+ private CharSequence mText;
private final long mTimestamp;
@Nullable
private final Person mSender;
@@ -8696,6 +8651,15 @@
}
/**
+ * Updates TextAppearance spans in the message text so it has sufficient contrast
+ * against its background.
+ * @hide
+ */
+ public void ensureColorContrast(int backgroundColor) {
+ mText = ContrastColorUtil.ensureColorSpanContrast(mText, backgroundColor);
+ }
+
+ /**
* Get the text to be used for this message, or the fallback text if a type and content
* Uri have been set
*/
@@ -8788,15 +8752,6 @@
return bundle;
}
- static Bundle[] getBundleArrayForMessages(List<Message> messages) {
- Bundle[] bundles = new Bundle[messages.size()];
- final int N = messages.size();
- for (int i = 0; i < N; i++) {
- bundles[i] = messages.get(i).toBundle();
- }
- return bundles;
- }
-
/**
* Returns a list of messages read from the given bundle list, e.g.
* {@link #EXTRA_MESSAGES} or {@link #EXTRA_HISTORIC_MESSAGES}.
@@ -9011,7 +8966,7 @@
if (!TextUtils.isEmpty(str)) {
contentView.setViewVisibility(rowIds[i], View.VISIBLE);
contentView.setTextViewText(rowIds[i],
- mBuilder.processTextSpans(mBuilder.processLegacyText(str)));
+ mBuilder.ensureColorSpanContrast(mBuilder.processLegacyText(str), p));
mBuilder.setTextViewColorSecondary(contentView, rowIds[i], p);
contentView.setViewPadding(rowIds[i], 0, topPadding, 0, 0);
if (first) {
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 3a60a69..9a34dbe 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -32,6 +32,7 @@
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorCallback;
import android.companion.virtual.sensor.VirtualSensorConfig;
+import android.companion.virtual.sensor.VirtualSensorDirectChannelCallback;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -381,7 +382,8 @@
}
/**
- * Returns the callback to get notified about changes in the sensor listeners.
+ * Returns the callback to get notified about changes in the sensor listeners or sensor direct
+ * channel configuration.
* @hide
*/
@Nullable
@@ -533,19 +535,29 @@
private int mAudioRecordingSessionId = AUDIO_SESSION_ID_GENERATE;
@NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
- @Nullable
- private IVirtualSensorCallback mVirtualSensorCallback;
+ @Nullable private Executor mVirtualSensorCallbackExecutor;
+ @Nullable private VirtualSensorCallback mVirtualSensorCallback;
+ @Nullable private Executor mVirtualSensorDirectChannelCallbackExecutor;
+ @Nullable private VirtualSensorDirectChannelCallback mVirtualSensorDirectChannelCallback;
private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub {
@NonNull
private final Executor mExecutor;
@NonNull
private final VirtualSensorCallback mCallback;
+ @Nullable
+ private final Executor mDirectChannelExecutor;
+ @Nullable
+ private final VirtualSensorDirectChannelCallback mDirectChannelCallback;
VirtualSensorCallbackDelegate(@NonNull @CallbackExecutor Executor executor,
- @NonNull VirtualSensorCallback callback) {
- mCallback = callback;
+ @NonNull VirtualSensorCallback callback,
+ @Nullable @CallbackExecutor Executor directChannelExecutor,
+ @Nullable VirtualSensorDirectChannelCallback directChannelCallback) {
mExecutor = executor;
+ mCallback = callback;
+ mDirectChannelExecutor = directChannelExecutor;
+ mDirectChannelCallback = directChannelCallback;
}
@Override
@@ -562,20 +574,29 @@
@Override
public void onDirectChannelCreated(int channelHandle,
@NonNull SharedMemory sharedMemory) {
- mExecutor.execute(
- () -> mCallback.onDirectChannelCreated(channelHandle, sharedMemory));
+ if (mDirectChannelCallback != null && mDirectChannelExecutor != null) {
+ mDirectChannelExecutor.execute(
+ () -> mDirectChannelCallback.onDirectChannelCreated(channelHandle,
+ sharedMemory));
+ }
}
@Override
public void onDirectChannelDestroyed(int channelHandle) {
- mExecutor.execute(() -> mCallback.onDirectChannelDestroyed(channelHandle));
+ if (mDirectChannelCallback != null && mDirectChannelExecutor != null) {
+ mDirectChannelExecutor.execute(
+ () -> mDirectChannelCallback.onDirectChannelDestroyed(channelHandle));
+ }
}
@Override
public void onDirectChannelConfigured(int channelHandle, @NonNull VirtualSensor sensor,
int rateLevel, int reportToken) {
- mExecutor.execute(() -> mCallback.onDirectChannelConfigured(
- channelHandle, sensor, rateLevel, reportToken));
+ if (mDirectChannelCallback != null && mDirectChannelExecutor != null) {
+ mDirectChannelExecutor.execute(
+ () -> mDirectChannelCallback.onDirectChannelConfigured(
+ channelHandle, sensor, rateLevel, reportToken));
+ }
}
}
@@ -783,20 +804,37 @@
}
/**
- * Sets the callback to get notified about changes in the sensor listeners.
+ * Sets the callback to get notified about changes in the sensor configuration.
*
* @param executor The executor where the callback is executed on.
* @param callback The callback to get notified when the state of the sensor
- * listeners has changed, see {@link VirtualSensorCallback}
+ * configuration has changed, see {@link VirtualSensorCallback}
*/
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setVirtualSensorCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull VirtualSensorCallback callback) {
- mVirtualSensorCallback = new VirtualSensorCallbackDelegate(
- Objects.requireNonNull(executor),
- Objects.requireNonNull(callback));
+ mVirtualSensorCallbackExecutor = Objects.requireNonNull(executor);
+ mVirtualSensorCallback = Objects.requireNonNull(callback);
+ return this;
+ }
+
+ /**
+ * Sets the callback to get notified about changes in
+ * {@link android.hardware.SensorDirectChannel} configuration.
+ *
+ * @param executor The executor where the callback is executed on.
+ * @param callback The callback to get notified when the state of the sensor
+ * configuration has changed, see {@link VirtualSensorDirectChannelCallback}
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setVirtualSensorDirectChannelCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull VirtualSensorDirectChannelCallback callback) {
+ mVirtualSensorDirectChannelCallbackExecutor = Objects.requireNonNull(executor);
+ mVirtualSensorDirectChannelCallback = Objects.requireNonNull(callback);
return this;
}
@@ -857,6 +895,7 @@
*/
@NonNull
public VirtualDeviceParams build() {
+ VirtualSensorCallbackDelegate virtualSensorCallbackDelegate = null;
if (!mVirtualSensorConfigs.isEmpty()) {
if (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
!= DEVICE_POLICY_CUSTOM) {
@@ -868,6 +907,22 @@
throw new IllegalArgumentException(
"VirtualSensorCallback is required for creating virtual sensors.");
}
+
+ for (int i = 0; i < mVirtualSensorConfigs.size(); ++i) {
+ if (mVirtualSensorConfigs.get(i).getDirectChannelTypesSupported() > 0) {
+ if (mVirtualSensorDirectChannelCallback == null) {
+ throw new IllegalArgumentException(
+ "VirtualSensorDirectChannelCallback is required for creating "
+ + "virtual sensors that support direct channel.");
+ }
+ break;
+ }
+ }
+ virtualSensorCallbackDelegate = new VirtualSensorCallbackDelegate(
+ mVirtualSensorCallbackExecutor,
+ mVirtualSensorCallback,
+ mVirtualSensorDirectChannelCallbackExecutor,
+ mVirtualSensorDirectChannelCallback);
}
if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
@@ -901,7 +956,7 @@
mName,
mDevicePolicies,
mVirtualSensorConfigs,
- mVirtualSensorCallback,
+ virtualSensorCallbackDelegate,
mAudioPlaybackSessionId,
mAudioRecordingSessionId);
}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorCallback.java b/core/java/android/companion/virtual/sensor/VirtualSensorCallback.java
index f7af283..e6bd6da 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorCallback.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorCallback.java
@@ -17,18 +17,14 @@
package android.companion.virtual.sensor;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.hardware.Sensor;
-import android.hardware.SensorDirectChannel;
-import android.os.MemoryFile;
-import android.os.SharedMemory;
import java.time.Duration;
/**
- * Interface for notifying the sensor owner about whether and how sensor events should be injected.
+ * Interface for notifying the virtual device owner about whether and how sensor events should be
+ * injected.
*
* <p>This callback can be used for controlling the sensor event injection - e.g. if the sensor is
* not enabled, then no events should be injected. Similarly, the rate and delay of the injected
@@ -45,6 +41,7 @@
* Called when the requested sensor event injection parameters have changed.
*
* <p>This is effectively called when the registered listeners to a virtual sensor have changed.
+ * The events for the corresponding sensor should be sent via {@link VirtualSensor#sendEvent}.
*
* @param sensor The sensor whose requested injection parameters have changed.
* @param enabled Whether the sensor is enabled. True if any listeners are currently registered,
@@ -55,74 +52,4 @@
*/
void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
@NonNull Duration samplingPeriod, @NonNull Duration batchReportLatency);
-
- /**
- * Called when a {@link android.hardware.SensorDirectChannel} is created.
- *
- * <p>The {@link android.hardware.SensorManager} instance used to create the direct channel must
- * be associated with the virtual device.
- *
- * <p>A typical order of callback invocations is:
- * <ul>
- * <li>{@code onDirectChannelCreated} - the channel handle and the associated shared memory
- * should be stored by the virtual device</li>
- * <li>{@code onDirectChannelConfigured} with a positive {@code rateLevel} - the virtual
- * device should start writing to the shared memory for the associated channel with the
- * requested parameters.</li>
- * <li>{@code onDirectChannelConfigured} with a {@code rateLevel = RATE_STOP} - the virtual
- * device should stop writing to the shared memory for the associated channel.</li>
- * <li>{@code onDirectChannelDestroyed} - the shared memory associated with the channel
- * handle should be closed.</li>
- * </ul>
- *
- * @param channelHandle Identifier of the newly created channel.
- * @param sharedMemory writable shared memory region.
- *
- * @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
- * @see #onDirectChannelConfigured
- * @see #onDirectChannelDestroyed
- */
- default void onDirectChannelCreated(@IntRange(from = 1) int channelHandle,
- @NonNull SharedMemory sharedMemory) {}
-
- /**
- * Called when a {@link android.hardware.SensorDirectChannel} is destroyed.
- *
- * <p>The virtual device must perform any clean-up and close the shared memory that was
- * received with the {@link #onDirectChannelCreated} callback and the corresponding
- * {@code channelHandle}.
- *
- * @param channelHandle Identifier of the channel that was destroyed.
- *
- * @see SensorDirectChannel#close()
- */
- default void onDirectChannelDestroyed(@IntRange(from = 1) int channelHandle) {}
-
- /**
- * Called when a {@link android.hardware.SensorDirectChannel} is configured.
- *
- * <p>Sensor events for the corresponding sensor should be written at the indicated rate to the
- * shared memory region that was received with the {@link #onDirectChannelCreated} callback and
- * the corresponding {@code channelHandle}. The events should be written in the correct format
- * and with the provided {@code reportToken} until the channel is reconfigured with
- * {@link SensorDirectChannel#RATE_STOP}.
- *
- * <p>The sensor must support direct channel in order for this callback to be invoked. Only
- * {@link MemoryFile} sensor direct channels are supported for virtual sensors.
- *
- * @param channelHandle Identifier of the channel that was configured.
- * @param sensor The sensor, for which the channel was configured.
- * @param rateLevel The rate level used to configure the direct sensor channel.
- * @param reportToken A positive sensor report token, used to differentiate between events from
- * different sensors within the same channel.
- *
- * @see VirtualSensorConfig.Builder#setHighestDirectReportRateLevel(int)
- * @see VirtualSensorConfig.Builder#setDirectChannelTypesSupported(int)
- * @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
- * @see #onDirectChannelCreated
- * @see SensorDirectChannel#configure(Sensor, int)
- */
- default void onDirectChannelConfigured(@IntRange(from = 1) int channelHandle,
- @NonNull VirtualSensor sensor, @SensorDirectChannel.RateLevel int rateLevel,
- @IntRange(from = 1) int reportToken) {}
}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
index 401e754..ef55ca9 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
@@ -50,14 +50,25 @@
private final String mName;
@Nullable
private final String mVendor;
+ private final float mMaximumRange;
+ private final float mResolution;
+ private final float mPower;
+ private final int mMinDelay;
+ private final int mMaxDelay;
private final int mFlags;
private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor,
+ float maximumRange, float resolution, float power, int minDelay, int maxDelay,
int flags) {
mType = type;
mName = name;
mVendor = vendor;
+ mMaximumRange = maximumRange;
+ mResolution = resolution;
+ mPower = power;
+ mMinDelay = minDelay;
+ mMaxDelay = maxDelay;
mFlags = flags;
}
@@ -65,6 +76,11 @@
mType = parcel.readInt();
mName = parcel.readString8();
mVendor = parcel.readString8();
+ mMaximumRange = parcel.readFloat();
+ mResolution = parcel.readFloat();
+ mPower = parcel.readFloat();
+ mMinDelay = parcel.readInt();
+ mMaxDelay = parcel.readInt();
mFlags = parcel.readInt();
}
@@ -78,6 +94,11 @@
parcel.writeInt(mType);
parcel.writeString8(mName);
parcel.writeString8(mVendor);
+ parcel.writeFloat(mMaximumRange);
+ parcel.writeFloat(mResolution);
+ parcel.writeFloat(mPower);
+ parcel.writeInt(mMinDelay);
+ parcel.writeInt(mMaxDelay);
parcel.writeInt(mFlags);
}
@@ -109,6 +130,47 @@
}
/**
+ * Returns maximum range of the sensor in the sensor's unit.
+ * @see Sensor#getMaximumRange
+ */
+ public float getMaximumRange() {
+ return mMaximumRange;
+ }
+
+ /**
+ * Returns The resolution of the sensor in the sensor's unit.
+ * @see Sensor#getResolution
+ */
+ public float getResolution() {
+ return mResolution;
+ }
+
+ /**
+ * Returns The power in mA used by this sensor while in use.
+ * @see Sensor#getPower
+ */
+ public float getPower() {
+ return mPower;
+ }
+
+ /**
+ * Returns The minimum delay allowed between two events in microseconds, or zero depending on
+ * the sensor type.
+ * @see Sensor#getMinDelay
+ */
+ public int getMinDelay() {
+ return mMinDelay;
+ }
+
+ /**
+ * Returns The maximum delay between two sensor events in microseconds.
+ * @see Sensor#getMaxDelay
+ */
+ public int getMaxDelay() {
+ return mMaxDelay;
+ }
+
+ /**
* Returns the highest supported direct report mode rate level of the sensor.
*
* @see Sensor#getHighestDirectReportRateLevel()
@@ -157,6 +219,11 @@
private final String mName;
@Nullable
private String mVendor;
+ private float mMaximumRange;
+ private float mResolution;
+ private float mPower;
+ private int mMinDelay;
+ private int mMaxDelay;
private int mFlags;
@SensorDirectChannel.RateLevel
int mHighestDirectReportRateLevel;
@@ -193,7 +260,8 @@
throw new IllegalArgumentException("Highest direct report rate level is "
+ "required for sensors with direct channel support.");
}
- return new VirtualSensorConfig(mType, mName, mVendor, mFlags);
+ return new VirtualSensorConfig(mType, mName, mVendor, mMaximumRange, mResolution,
+ mPower, mMinDelay, mMaxDelay, mFlags);
}
/**
@@ -206,6 +274,56 @@
}
/**
+ * Sets the maximum range of the sensor in the sensor's unit.
+ * @see Sensor#getMaximumRange
+ */
+ @NonNull
+ public VirtualSensorConfig.Builder setMaximumRange(float maximumRange) {
+ mMaximumRange = maximumRange;
+ return this;
+ }
+
+ /**
+ * Sets the resolution of the sensor in the sensor's unit.
+ * @see Sensor#getResolution
+ */
+ @NonNull
+ public VirtualSensorConfig.Builder setResolution(float resolution) {
+ mResolution = resolution;
+ return this;
+ }
+
+ /**
+ * Sets the power in mA used by this sensor while in use.
+ * @see Sensor#getPower
+ */
+ @NonNull
+ public VirtualSensorConfig.Builder setPower(float power) {
+ mPower = power;
+ return this;
+ }
+
+ /**
+ * Sets the minimum delay allowed between two events in microseconds.
+ * @see Sensor#getMinDelay
+ */
+ @NonNull
+ public VirtualSensorConfig.Builder setMinDelay(int minDelay) {
+ mMinDelay = minDelay;
+ return this;
+ }
+
+ /**
+ * Sets the maximum delay between two sensor events in microseconds.
+ * @see Sensor#getMaxDelay
+ */
+ @NonNull
+ public VirtualSensorConfig.Builder setMaxDelay(int maxDelay) {
+ mMaxDelay = maxDelay;
+ return this;
+ }
+
+ /**
* Sets the highest supported rate level for direct sensor report.
*
* @see VirtualSensorConfig#getHighestDirectReportRateLevel()
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelCallback.java b/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelCallback.java
new file mode 100644
index 0000000..d352f94f
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelCallback.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.virtual.sensor;
+
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.hardware.Sensor;
+import android.hardware.SensorDirectChannel;
+import android.os.MemoryFile;
+import android.os.SharedMemory;
+
+/**
+ * Interface for notifying the virtual device owner about any {@link SensorDirectChannel} events.
+ *
+ * <p>This callback can be used for controlling the sensor event injection to direct channels. A
+ * typical order of callback invocations is:
+ * <ul>
+ * <li>{@code onDirectChannelCreated} - the channel handle and the associated shared memory
+ * should be stored by the virtual device</li>
+ * <li>{@code onDirectChannelConfigured} with a positive {@code rateLevel} - the virtual
+ * device should start writing to the shared memory for the associated channel with the
+ * requested parameters.</li>
+ * <li>{@code onDirectChannelConfigured} with a {@code rateLevel = RATE_STOP} - the virtual
+ * device should stop writing to the shared memory for the associated channel.</li>
+ * <li>{@code onDirectChannelDestroyed} - the shared memory associated with the channel
+ * handle should be closed.</li>
+ * </ul>
+ *
+ * <p>The callback is tied to the VirtualDevice's lifetime as the virtual sensors are created when
+ * the device is created and destroyed when the device is destroyed.
+ *
+ * @hide
+ */
+@SystemApi
+public interface VirtualSensorDirectChannelCallback {
+ /**
+ * Called when a {@link android.hardware.SensorDirectChannel} is created.
+ *
+ * <p>The {@link android.hardware.SensorManager} instance used to create the direct channel must
+ * be associated with the virtual device.
+ *
+ * @param channelHandle Identifier of the newly created channel.
+ * @param sharedMemory writable shared memory region.
+ *
+ * @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
+ * @see #onDirectChannelConfigured
+ * @see #onDirectChannelDestroyed
+ */
+ void onDirectChannelCreated(@IntRange(from = 1) int channelHandle,
+ @NonNull SharedMemory sharedMemory);
+
+ /**
+ * Called when a {@link android.hardware.SensorDirectChannel} is destroyed.
+ *
+ * <p>The virtual device must perform any clean-up and close the shared memory that was
+ * received with the {@link #onDirectChannelCreated} callback and the corresponding
+ * {@code channelHandle}.
+ *
+ * @param channelHandle Identifier of the channel that was destroyed.
+ *
+ * @see SensorDirectChannel#close()
+ */
+ void onDirectChannelDestroyed(@IntRange(from = 1) int channelHandle);
+
+ /**
+ * Called when a {@link android.hardware.SensorDirectChannel} is configured.
+ *
+ * <p>Sensor events for the corresponding sensor should be written at the indicated rate to the
+ * shared memory region that was received with the {@link #onDirectChannelCreated} callback and
+ * the corresponding {@code channelHandle}. The events should be written in the correct format
+ * and with the provided {@code reportToken} until the channel is reconfigured with
+ * {@link SensorDirectChannel#RATE_STOP}.
+ *
+ * <p>The sensor must support direct channel in order for this callback to be invoked. Only
+ * {@link MemoryFile} sensor direct channels are supported for virtual sensors.
+ *
+ * @param channelHandle Identifier of the channel that was configured.
+ * @param sensor The sensor, for which the channel was configured.
+ * @param rateLevel The rate level used to configure the direct sensor channel.
+ * @param reportToken A positive sensor report token, used to differentiate between events from
+ * different sensors within the same channel.
+ *
+ * @see VirtualSensorConfig.Builder#setHighestDirectReportRateLevel(int)
+ * @see VirtualSensorConfig.Builder#setDirectChannelTypesSupported(int)
+ * @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
+ * @see #onDirectChannelCreated
+ * @see SensorDirectChannel#configure(Sensor, int)
+ */
+ void onDirectChannelConfigured(@IntRange(from = 1) int channelHandle,
+ @NonNull VirtualSensor sensor, @SensorDirectChannel.RateLevel int rateLevel,
+ @IntRange(from = 1) int reportToken);
+}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java b/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java
new file mode 100644
index 0000000..6aed96f
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorDirectChannelWriter.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.virtual.sensor;
+
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.hardware.SensorDirectChannel;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Helper class for writing sensor events to the relevant configured direct channels.
+ *
+ * <p>The virtual device owner can forward the {@link VirtualSensorDirectChannelCallback}
+ * invocations to a {@link VirtualSensorDirectChannelWriter} instance and use that writer to
+ * write the events from the relevant sensors directly to the shared memory regions of the
+ * corresponding {@link SensorDirectChannel} instances.
+ *
+ * @see android.hardware.SensorDirectChannel#configure
+ * @see VirtualSensorDirectChannelCallback
+ *
+ * @hide
+ */
+@SystemApi
+public final class VirtualSensorDirectChannelWriter implements AutoCloseable {
+
+ private static final String TAG = "VirtualSensorWriter";
+
+ private static final long UINT32_MAX = 4294967295L;
+
+ // Mapping from channel handle to channel shared memory region.
+ @GuardedBy("mChannelsLock")
+ private final SparseArray<SharedMemoryWrapper> mChannels = new SparseArray<>();
+ private final Object mChannelsLock = new Object();
+
+ // Mapping from sensor handle to channel handle to direct sensor configuration.
+ @GuardedBy("mChannelsLock")
+ private final SparseArray<SparseArray<DirectChannelConfiguration>> mConfiguredChannels =
+ new SparseArray<>();
+
+ @Override
+ public void close() {
+ synchronized (mChannelsLock) {
+ for (int i = 0; i < mChannels.size(); ++i) {
+ mChannels.valueAt(i).close();
+ }
+ mChannels.clear();
+ mConfiguredChannels.clear();
+ }
+ }
+
+ /**
+ * Adds a sensor direct channel handle and the relevant shared memory region.
+ *
+ * @throws ErrnoException if the mapping of the shared memory region failed.
+ *
+ * @see VirtualSensorDirectChannelCallback#onDirectChannelCreated
+ */
+ public void addChannel(@IntRange(from = 1) int channelHandle,
+ @NonNull SharedMemory sharedMemory) throws ErrnoException {
+ synchronized (mChannelsLock) {
+ if (mChannels.contains(channelHandle)) {
+ Log.w(TAG, "Channel with handle " + channelHandle + " already added.");
+ } else {
+ mChannels.put(channelHandle,
+ new SharedMemoryWrapper(Objects.requireNonNull(sharedMemory)));
+ }
+ }
+ }
+
+ /**
+ * Removes a sensor direct channel indicated by the handle and closes the relevant shared memory
+ * region.
+ *
+ * @see VirtualSensorDirectChannelCallback#onDirectChannelDestroyed
+ */
+ public void removeChannel(@IntRange(from = 1) int channelHandle) {
+ synchronized (mChannelsLock) {
+ SharedMemoryWrapper sharedMemoryWrapper = mChannels.removeReturnOld(channelHandle);
+ if (sharedMemoryWrapper != null) {
+ sharedMemoryWrapper.close();
+ }
+ for (int i = 0; i < mConfiguredChannels.size(); ++i) {
+ mConfiguredChannels.valueAt(i).remove(channelHandle);
+ }
+ }
+ }
+
+ /**
+ * Configures a sensor direct channel indicated by the handle and prepares it for sensor event
+ * writes for the given sensor.
+ *
+ * @return Whether the configuration was successful.
+ *
+ * @see VirtualSensorDirectChannelCallback#onDirectChannelConfigured
+ */
+ public boolean configureChannel(@IntRange(from = 1) int channelHandle,
+ @NonNull VirtualSensor sensor, @SensorDirectChannel.RateLevel int rateLevel,
+ @IntRange(from = 1) int reportToken) {
+ synchronized (mChannelsLock) {
+ SparseArray<DirectChannelConfiguration> configs = mConfiguredChannels.get(
+ Objects.requireNonNull(sensor).getHandle());
+ if (rateLevel == SensorDirectChannel.RATE_STOP) {
+ if (configs == null || configs.removeReturnOld(channelHandle) == null) {
+ Log.w(TAG, "Channel configuration failed - channel with handle "
+ + channelHandle + " not found");
+ return false;
+ }
+ return true;
+ }
+
+ if (configs == null) {
+ configs = new SparseArray<>();
+ mConfiguredChannels.put(sensor.getHandle(), configs);
+ }
+
+ SharedMemoryWrapper sharedMemoryWrapper = mChannels.get(channelHandle);
+ if (sharedMemoryWrapper == null) {
+ Log.w(TAG, "Channel configuration failed - channel with handle "
+ + channelHandle + " not found");
+ return false;
+ }
+ configs.put(channelHandle, new DirectChannelConfiguration(
+ reportToken, sensor.getType(), sharedMemoryWrapper));
+ return true;
+ }
+ }
+
+ /**
+ * Writes a sensor event for the given sensor to all configured sensor direct channels for that
+ * sensor.
+ *
+ * @return Whether the write was successful.
+ *
+ */
+ public boolean writeSensorEvent(@NonNull VirtualSensor sensor,
+ @NonNull VirtualSensorEvent event) {
+ Objects.requireNonNull(event);
+ synchronized (mChannelsLock) {
+ SparseArray<DirectChannelConfiguration> configs = mConfiguredChannels.get(
+ Objects.requireNonNull(sensor).getHandle());
+ if (configs == null || configs.size() == 0) {
+ Log.w(TAG, "Sensor event write failed - no direct sensor channels configured for "
+ + "sensor " + sensor.getName());
+ return false;
+ }
+
+ for (int i = 0; i < configs.size(); ++i) {
+ configs.valueAt(i).write(Objects.requireNonNull(event));
+ }
+ }
+ return true;
+ }
+
+ private static final class SharedMemoryWrapper {
+
+ private static final int SENSOR_EVENT_SIZE = 104;
+
+ // The limit of number of values for a single sensor event.
+ private static final int MAXIMUM_NUMBER_OF_SENSOR_VALUES = 16;
+
+ @GuardedBy("mWriteLock")
+ private final SharedMemory mSharedMemory;
+ @GuardedBy("mWriteLock")
+ private int mWriteOffset = 0;
+ @GuardedBy("mWriteLock")
+ private final ByteBuffer mEventBuffer = ByteBuffer.allocate(SENSOR_EVENT_SIZE);
+ @GuardedBy("mWriteLock")
+ private final ByteBuffer mMemoryMapping;
+ private final Object mWriteLock = new Object();
+
+ SharedMemoryWrapper(SharedMemory sharedMemory) throws ErrnoException {
+ mSharedMemory = sharedMemory;
+ mMemoryMapping = mSharedMemory.mapReadWrite();
+ mEventBuffer.order(ByteOrder.nativeOrder());
+ }
+
+ void close() {
+ synchronized (mWriteLock) {
+ mSharedMemory.close();
+ }
+ }
+
+ void write(int reportToken, int sensorType, long eventCounter, VirtualSensorEvent event) {
+ synchronized (mWriteLock) {
+ mEventBuffer.position(0);
+ mEventBuffer.putInt(SENSOR_EVENT_SIZE);
+ mEventBuffer.putInt(reportToken);
+ mEventBuffer.putInt(sensorType);
+ mEventBuffer.putInt((int) (eventCounter & UINT32_MAX));
+ mEventBuffer.putLong(event.getTimestampNanos());
+
+ for (int i = 0; i < MAXIMUM_NUMBER_OF_SENSOR_VALUES; ++i) {
+ if (i < event.getValues().length) {
+ mEventBuffer.putFloat(event.getValues()[i]);
+ } else {
+ mEventBuffer.putFloat(0f);
+ }
+ }
+ mEventBuffer.putInt(0);
+
+ mMemoryMapping.position(mWriteOffset);
+ mMemoryMapping.put(mEventBuffer.array(), 0, SENSOR_EVENT_SIZE);
+
+ mWriteOffset += SENSOR_EVENT_SIZE;
+ if (mWriteOffset + SENSOR_EVENT_SIZE >= mSharedMemory.getSize()) {
+ mWriteOffset = 0;
+ }
+ }
+ }
+ }
+
+ private static final class DirectChannelConfiguration {
+ private final int mReportToken;
+ private final int mSensorType;
+ private final AtomicLong mEventCounter;
+ private final SharedMemoryWrapper mSharedMemoryWrapper;
+
+ DirectChannelConfiguration(int reportToken, int sensorType,
+ SharedMemoryWrapper sharedMemoryWrapper) {
+ mReportToken = reportToken;
+ mSensorType = sensorType;
+ mEventCounter = new AtomicLong(1);
+ mSharedMemoryWrapper = sharedMemoryWrapper;
+ }
+
+ void write(VirtualSensorEvent event) {
+ long currentCounter = mEventCounter.getAcquire();
+ mSharedMemoryWrapper.write(mReportToken, mSensorType, currentCounter++, event);
+ if (currentCounter == UINT32_MAX + 1) {
+ currentCounter = 1;
+ }
+ mEventCounter.setRelease(currentCounter);
+ }
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fc75323..3b2ea78 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -7873,4 +7873,15 @@
public boolean isConfigurationContext() {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
+
+ /**
+ * Closes temporary system dialogs. Some examples of temporary system dialogs are the
+ * notification window-shade and the recent tasks dialog.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS)
+ public void closeSystemDialogs() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 21de5cf..4327c7a 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1484,4 +1484,15 @@
// Do nothing if the callback hasn't been registered to Application Context by
// super.unregisterComponentCallbacks() for Application that is targeting prior to T.
}
+
+ /**
+ * Closes temporary system dialogs. Some examples of temporary system dialogs are the
+ * notification window-shade and the recent tasks dialog.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS)
+ public void closeSystemDialogs() {
+ mBase.closeSystemDialogs();
+ }
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 410994d..1ba84c5 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -353,12 +353,13 @@
*/
@UnsupportedAppUsage
void setComponentEnabledSetting(in ComponentName componentName,
- in int newState, in int flags, int userId);
+ in int newState, in int flags, int userId, String callingPackage);
/**
* As per {@link android.content.pm.PackageManager#setComponentEnabledSettings}.
*/
- void setComponentEnabledSettings(in List<ComponentEnabledSetting> settings, int userId);
+ void setComponentEnabledSettings(in List<ComponentEnabledSetting> settings, int userId,
+ String callingPackage);
/**
* As per {@link android.content.pm.PackageManager#getComponentEnabledSetting}.
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index dfc7b464..ef3842a 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1453,6 +1453,16 @@
}
/**
+ * @hide
+ */
+ Configuration[] getSizeAndUiModeConfigurations() {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetSizeAndUiModeConfigurations(mObject);
+ }
+ }
+
+ /**
* Change the configuration used when retrieving resources. Not for use by
* applications.
* @hide
@@ -1604,6 +1614,7 @@
private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
+ private static native @Nullable Configuration[] nativeGetSizeAndUiModeConfigurations(long ptr);
private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled);
private static native @Nullable String nativeGetLastResourceResolution(long ptr);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d6934bc..885060f 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2232,6 +2232,11 @@
return mResourcesImpl.getSizeConfigurations();
}
+ /** @hide */
+ public Configuration[] getSizeAndUiModeConfigurations() {
+ return mResourcesImpl.getSizeAndUiModeConfigurations();
+ }
+
/**
* Return the compatibility mode information for the application.
* The returned object should be treated as read-only.
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 2170886..3a2863e 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -207,6 +207,10 @@
return mAssets.getSizeConfigurations();
}
+ Configuration[] getSizeAndUiModeConfigurations() {
+ return mAssets.getSizeAndUiModeConfigurations();
+ }
+
CompatibilityInfo getCompatibilityInfo() {
return mDisplayAdjustments.getCompatibilityInfo();
}
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java
index 49ae9e9..09d2db8 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/ui/RequestInfo.java
@@ -74,13 +74,30 @@
@NonNull
private final String mAppPackageName;
+ private final boolean mHasPermissionToOverrideDefault;
+
/** Creates new {@code RequestInfo} for a create-credential flow. */
@NonNull
public static RequestInfo newCreateRequestInfo(
@NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest,
@NonNull String appPackageName) {
return new RequestInfo(
- token, TYPE_CREATE, appPackageName, createCredentialRequest, null);
+ token, TYPE_CREATE, appPackageName, createCredentialRequest, null,
+ /*hasPermissionToOverrideDefault=*/ false);
+ }
+
+ /**
+ * Creates new {@code RequestInfo} for a create-credential flow.
+ *
+ * @hide
+ */
+ @NonNull
+ public static RequestInfo newCreateRequestInfo(
+ @NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest,
+ @NonNull String appPackageName, boolean hasPermissionToOverrideDefault) {
+ return new RequestInfo(
+ token, TYPE_CREATE, appPackageName, createCredentialRequest, null,
+ hasPermissionToOverrideDefault);
}
/** Creates new {@code RequestInfo} for a get-credential flow. */
@@ -89,7 +106,18 @@
@NonNull IBinder token, @NonNull GetCredentialRequest getCredentialRequest,
@NonNull String appPackageName) {
return new RequestInfo(
- token, TYPE_GET, appPackageName, null, getCredentialRequest);
+ token, TYPE_GET, appPackageName, null, getCredentialRequest,
+ /*hasPermissionToOverrideDefault=*/ false);
+ }
+
+
+ /**
+ * Returns whether the calling package has the permission
+ *
+ * @hide
+ */
+ public boolean hasPermissionToOverrideDefault() {
+ return mHasPermissionToOverrideDefault;
}
/** Returns the request token matching the user request. */
@@ -132,12 +160,14 @@
private RequestInfo(@NonNull IBinder token, @NonNull @RequestType String type,
@NonNull String appPackageName,
@Nullable CreateCredentialRequest createCredentialRequest,
- @Nullable GetCredentialRequest getCredentialRequest) {
+ @Nullable GetCredentialRequest getCredentialRequest,
+ boolean hasPermissionToOverrideDefault) {
mToken = token;
mType = type;
mAppPackageName = appPackageName;
mCreateCredentialRequest = createCredentialRequest;
mGetCredentialRequest = getCredentialRequest;
+ mHasPermissionToOverrideDefault = hasPermissionToOverrideDefault;
}
private RequestInfo(@NonNull Parcel in) {
@@ -157,6 +187,7 @@
AnnotationValidations.validate(NonNull.class, null, mAppPackageName);
mCreateCredentialRequest = createCredentialRequest;
mGetCredentialRequest = getCredentialRequest;
+ mHasPermissionToOverrideDefault = in.readBoolean();
}
@Override
@@ -166,6 +197,7 @@
dest.writeString8(mAppPackageName);
dest.writeTypedObject(mCreateCredentialRequest, flags);
dest.writeTypedObject(mGetCredentialRequest, flags);
+ dest.writeBoolean(mHasPermissionToOverrideDefault);
}
@Override
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 5dc3825..8a4a0e4 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -34,12 +34,10 @@
import android.hardware.BatteryState;
import android.hardware.SensorManager;
import android.hardware.lights.LightsManager;
-import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.InputEventInjectionSync;
-import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Vibrator;
@@ -392,12 +390,7 @@
* @hide
*/
public boolean isInputDeviceEnabled(int id) {
- try {
- return mIm.isInputDeviceEnabled(id);
- } catch (RemoteException ex) {
- Log.w(TAG, "Could not check enabled status of input device with id = " + id);
- throw ex.rethrowFromSystemServer();
- }
+ return mGlobal.isInputDeviceEnabled(id);
}
/**
@@ -411,12 +404,7 @@
* @hide
*/
public void enableInputDevice(int id) {
- try {
- mIm.enableInputDevice(id);
- } catch (RemoteException ex) {
- Log.w(TAG, "Could not enable input device with id = " + id);
- throw ex.rethrowFromSystemServer();
- }
+ mGlobal.enableInputDevice(id);
}
/**
@@ -430,12 +418,7 @@
* @hide
*/
public void disableInputDevice(int id) {
- try {
- mIm.disableInputDevice(id);
- } catch (RemoteException ex) {
- Log.w(TAG, "Could not disable input device with id = " + id);
- throw ex.rethrowFromSystemServer();
- }
+ mGlobal.disableInputDevice(id);
}
/**
@@ -1007,13 +990,7 @@
* @hide
*/
public boolean[] deviceHasKeys(int id, int[] keyCodes) {
- boolean[] ret = new boolean[keyCodes.length];
- try {
- mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- return ret;
+ return mGlobal.deviceHasKeys(id, keyCodes);
}
/**
@@ -1038,11 +1015,7 @@
* @hide
*/
public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) {
- try {
- return mIm.getKeyCodeForKeyLocation(deviceId, locationKeyCode);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mGlobal.getKeyCodeForKeyLocation(deviceId, locationKeyCode);
}
/**
@@ -1075,20 +1048,7 @@
*/
@RequiresPermission(Manifest.permission.INJECT_EVENTS)
public boolean injectInputEvent(InputEvent event, int mode, int targetUid) {
- if (event == null) {
- throw new IllegalArgumentException("event must not be null");
- }
- if (mode != InputEventInjectionSync.NONE
- && mode != InputEventInjectionSync.WAIT_FOR_FINISHED
- && mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
- throw new IllegalArgumentException("mode is invalid");
- }
-
- try {
- return mIm.injectInputEventToTarget(event, mode, targetUid);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ return mGlobal.injectInputEvent(event, mode, targetUid);
}
/**
@@ -1114,7 +1074,7 @@
@RequiresPermission(Manifest.permission.INJECT_EVENTS)
@UnsupportedAppUsage
public boolean injectInputEvent(InputEvent event, int mode) {
- return injectInputEvent(event, mode, Process.INVALID_UID);
+ return mGlobal.injectInputEvent(event, mode);
}
/**
@@ -1149,20 +1109,12 @@
*/
@UnsupportedAppUsage
public void setPointerIconType(int iconId) {
- try {
- mIm.setPointerIconType(iconId);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ mGlobal.setPointerIconType(iconId);
}
/** @hide */
public void setCustomPointerIcon(PointerIcon icon) {
- try {
- mIm.setCustomPointerIcon(icon);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ mGlobal.setCustomPointerIcon(icon);
}
/**
@@ -1191,11 +1143,7 @@
* @hide
*/
public void requestPointerCapture(IBinder windowToken, boolean enable) {
- try {
- mIm.requestPointerCapture(windowToken, enable);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ mGlobal.requestPointerCapture(windowToken, enable);
}
/**
@@ -1204,11 +1152,7 @@
* @hide
*/
public InputMonitor monitorGestureInput(String name, int displayId) {
- try {
- return mIm.monitorGestureInput(new Binder(), name, displayId);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ return mGlobal.monitorGestureInput(name, displayId);
}
/**
@@ -1313,12 +1257,9 @@
* @hide
*/
@TestApi
- public void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) {
- try {
- mIm.addUniqueIdAssociation(inputPort, displayUniqueId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ public void addUniqueIdAssociation(@NonNull String inputPort,
+ @NonNull String displayUniqueId) {
+ mGlobal.addUniqueIdAssociation(inputPort, displayUniqueId);
}
/**
@@ -1331,11 +1272,7 @@
*/
@TestApi
public void removeUniqueIdAssociation(@NonNull String inputPort) {
- try {
- mIm.removeUniqueIdAssociation(inputPort);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mGlobal.removeUniqueIdAssociation(inputPort);
}
/**
@@ -1361,11 +1298,7 @@
@RequiresPermission(Manifest.permission.BLUETOOTH)
@Nullable
public String getInputDeviceBluetoothAddress(int deviceId) {
- try {
- return mIm.getInputDeviceBluetoothAddress(deviceId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mGlobal.getInputDeviceBluetoothAddress(deviceId);
}
/**
@@ -1423,11 +1356,7 @@
* @hide
*/
public void cancelCurrentTouch() {
- try {
- mIm.cancelCurrentTouch();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mGlobal.cancelCurrentTouch();
}
/**
@@ -1451,11 +1380,7 @@
*/
@RequiresPermission(Manifest.permission.MONITOR_INPUT)
public void pilferPointers(IBinder inputChannelToken) {
- try {
- mIm.pilferPointers(inputChannelToken);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mGlobal.pilferPointers(inputChannelToken);
}
/**
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 08d81bd..6e7e90e 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -30,19 +30,27 @@
import android.hardware.lights.Light;
import android.hardware.lights.LightState;
import android.hardware.lights.LightsRequest;
+import android.os.Binder;
import android.os.CombinedVibration;
import android.os.Handler;
import android.os.IBinder;
import android.os.IVibratorStateListener;
+import android.os.InputEventInjectionSync;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.os.VibratorManager;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputMonitor;
+import android.view.PointerIcon;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.SomeArgs;
@@ -359,6 +367,42 @@
}
/**
+ * @see InputManager#isInputDeviceEnabled(int)
+ */
+ public boolean isInputDeviceEnabled(int id) {
+ try {
+ return mIm.isInputDeviceEnabled(id);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not check enabled status of input device with id = " + id);
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#enableInputDevice(int)
+ */
+ public void enableInputDevice(int id) {
+ try {
+ mIm.enableInputDevice(id);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not enable input device with id = " + id);
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#disableInputDevice(int)
+ */
+ public void disableInputDevice(int id) {
+ try {
+ mIm.disableInputDevice(id);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not disable input device with id = " + id);
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @see InputManager#getInputDeviceByDescriptor
*/
InputDevice getInputDeviceByDescriptor(String descriptor) {
@@ -672,7 +716,7 @@
* @see InputManager#getInputDeviceBatteryState(int, boolean)
*/
@NonNull
- BatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) {
+ public BatteryState getInputDeviceBatteryState(int deviceId, boolean hasBattery) {
if (!hasBattery) {
return new LocalBatteryState();
}
@@ -835,7 +879,7 @@
* @see InputManager#getInputDeviceSensorManager(int)
*/
@NonNull
- SensorManager getInputDeviceSensorManager(int deviceId) {
+ public SensorManager getInputDeviceSensorManager(int deviceId) {
if (mInputDeviceSensorManager == null) {
mInputDeviceSensorManager = new InputDeviceSensorManager(this);
}
@@ -980,6 +1024,21 @@
}
}
+ /**
+ * @see InputManager#getInputDeviceVibrator(int, int)
+ */
+ public Vibrator getInputDeviceVibrator(int deviceId, int vibratorId) {
+ return new InputDeviceVibrator(deviceId, vibratorId);
+ }
+
+ /**
+ * @see InputManager#getInputDeviceVibratorManager(int)
+ */
+ @NonNull
+ public VibratorManager getInputDeviceVibratorManager(int deviceId) {
+ return new InputDeviceVibratorManager(deviceId);
+ }
+
/*
* Get the list of device vibrators
* @return The list of vibrators IDs
@@ -1057,4 +1116,158 @@
throw ex.rethrowFromSystemServer();
}
}
+
+ /**
+ * @see InputManager#deviceHasKeys(int, int[])
+ */
+ public boolean[] deviceHasKeys(int id, int[] keyCodes) {
+ boolean[] ret = new boolean[keyCodes.length];
+ try {
+ mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return ret;
+ }
+
+ /**
+ * @see InputManager#getKeyCodeforKeyLocation(int, int)
+ */
+ public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) {
+ try {
+ return mIm.getKeyCodeForKeyLocation(deviceId, locationKeyCode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#injectInputEvent(InputEvent, int, int)
+ */
+
+ public boolean injectInputEvent(InputEvent event, int mode, int targetUid) {
+ if (event == null) {
+ throw new IllegalArgumentException("event must not be null");
+ }
+ if (mode != InputEventInjectionSync.NONE
+ && mode != InputEventInjectionSync.WAIT_FOR_FINISHED
+ && mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
+ throw new IllegalArgumentException("mode is invalid");
+ }
+
+ try {
+ return mIm.injectInputEventToTarget(event, mode, targetUid);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#injectInputEvent(InputEvent, int)
+ */
+ public boolean injectInputEvent(InputEvent event, int mode) {
+ return injectInputEvent(event, mode, Process.INVALID_UID);
+ }
+
+ /**
+ * @see InputManager#setPointerIconType(int)
+ */
+ public void setPointerIconType(int iconId) {
+ try {
+ mIm.setPointerIconType(iconId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#setCustomPointerIcon(PointerIcon)
+ */
+ public void setCustomPointerIcon(PointerIcon icon) {
+ try {
+ mIm.setCustomPointerIcon(icon);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#requestPointerCapture(IBinder, boolean)
+ */
+ void requestPointerCapture(IBinder windowToken, boolean enable) {
+ try {
+ mIm.requestPointerCapture(windowToken, enable);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see Inputmanager#monitorGestureInput(String, int)
+ */
+ InputMonitor monitorGestureInput(String name, int displayId) {
+ try {
+ return mIm.monitorGestureInput(new Binder(), name, displayId);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#addUniqueIdAssociation(String, String)
+ */
+ void addUniqueIdAssociation(@NonNull String inputPort, @NonNull String displayUniqueId) {
+ try {
+ mIm.addUniqueIdAssociation(inputPort, displayUniqueId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#removeUniqueIdAssociation(String)
+ */
+ public void removeUniqueIdAssociation(@NonNull String inputPort) {
+ try {
+ mIm.removeUniqueIdAssociation(inputPort);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#getInputDeviceBluetoothAddress(int)
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @Nullable
+ public String getInputDeviceBluetoothAddress(int deviceId) {
+ try {
+ return mIm.getInputDeviceBluetoothAddress(deviceId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#cancelCurrentTouch()
+ */
+ void cancelCurrentTouch() {
+ try {
+ mIm.cancelCurrentTouch();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see InputManager#pilferPointers(IBinder)
+ */
+ @RequiresPermission(Manifest.permission.MONITOR_INPUT)
+ void pilferPointers(IBinder inputChannelToken) {
+ try {
+ mIm.pilferPointers(inputChannelToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/hardware/input/VirtualKeyEvent.java b/core/java/android/hardware/input/VirtualKeyEvent.java
index dc30e55..dc47f08 100644
--- a/core/java/android/hardware/input/VirtualKeyEvent.java
+++ b/core/java/android/hardware/input/VirtualKeyEvent.java
@@ -21,6 +21,8 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
+import android.view.InputEvent;
import android.view.KeyEvent;
import java.lang.annotation.Retention;
@@ -177,21 +179,25 @@
private final @Action int mAction;
private final int mKeyCode;
+ private final long mEventTimeNanos;
- private VirtualKeyEvent(@Action int action, int keyCode) {
+ private VirtualKeyEvent(@Action int action, int keyCode, long eventTimeNanos) {
mAction = action;
mKeyCode = keyCode;
+ mEventTimeNanos = eventTimeNanos;
}
private VirtualKeyEvent(@NonNull Parcel parcel) {
mAction = parcel.readInt();
mKeyCode = parcel.readInt();
+ mEventTimeNanos = parcel.readLong();
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
parcel.writeInt(mAction);
parcel.writeInt(mKeyCode);
+ parcel.writeLong(mEventTimeNanos);
}
@Override
@@ -214,12 +220,23 @@
}
/**
+ * Returns the time this event occurred, in the {@link SystemClock#uptimeMillis()} time base but
+ * with nanosecond (instead of millisecond) precision.
+ *
+ * @see InputEvent#getEventTime()
+ */
+ public long getEventTimeNanos() {
+ return mEventTimeNanos;
+ }
+
+ /**
* Builder for {@link VirtualKeyEvent}.
*/
public static final class Builder {
private @Action int mAction = ACTION_UNKNOWN;
private int mKeyCode = -1;
+ private long mEventTimeNanos = 0L;
/**
* Creates a {@link VirtualKeyEvent} object with the current builder configuration.
@@ -229,7 +246,7 @@
throw new IllegalArgumentException(
"Cannot build virtual key event with unset fields");
}
- return new VirtualKeyEvent(mAction, mKeyCode);
+ return new VirtualKeyEvent(mAction, mKeyCode, mEventTimeNanos);
}
/**
@@ -254,6 +271,23 @@
mAction = action;
return this;
}
+
+ /**
+ * Sets the time (in nanoseconds) when this specific event was generated. This may be
+ * obtained from {@link SystemClock#uptimeMillis()} (with nanosecond precision instead of
+ * millisecond), but can be different depending on the use case.
+ * This field is optional and can be omitted.
+ *
+ * @return this builder, to allow for chaining of calls
+ * @see InputEvent#getEventTime()
+ */
+ public @NonNull Builder setEventTimeNanos(long eventTimeNanos) {
+ if (eventTimeNanos < 0L) {
+ throw new IllegalArgumentException("Event time cannot be negative");
+ }
+ mEventTimeNanos = eventTimeNanos;
+ return this;
+ }
}
public static final @NonNull Parcelable.Creator<VirtualKeyEvent> CREATOR =
diff --git a/core/java/android/hardware/input/VirtualMouseButtonEvent.java b/core/java/android/hardware/input/VirtualMouseButtonEvent.java
index 2e094cf..dfdd3b4 100644
--- a/core/java/android/hardware/input/VirtualMouseButtonEvent.java
+++ b/core/java/android/hardware/input/VirtualMouseButtonEvent.java
@@ -21,6 +21,8 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
+import android.view.InputEvent;
import android.view.MotionEvent;
import java.lang.annotation.Retention;
@@ -81,21 +83,26 @@
private final @Action int mAction;
private final @Button int mButtonCode;
+ private final long mEventTimeNanos;
- private VirtualMouseButtonEvent(@Action int action, @Button int buttonCode) {
+ private VirtualMouseButtonEvent(@Action int action, @Button int buttonCode,
+ long eventTimeNanos) {
mAction = action;
mButtonCode = buttonCode;
+ mEventTimeNanos = eventTimeNanos;
}
private VirtualMouseButtonEvent(@NonNull Parcel parcel) {
mAction = parcel.readInt();
mButtonCode = parcel.readInt();
+ mEventTimeNanos = parcel.readLong();
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
parcel.writeInt(mAction);
parcel.writeInt(mButtonCode);
+ parcel.writeLong(mEventTimeNanos);
}
@Override
@@ -118,12 +125,23 @@
}
/**
+ * Returns the time this event occurred, in the {@link SystemClock#uptimeMillis()} time base but
+ * with nanosecond (instead of millisecond) precision.
+ *
+ * @see InputEvent#getEventTime()
+ */
+ public long getEventTimeNanos() {
+ return mEventTimeNanos;
+ }
+
+ /**
* Builder for {@link VirtualMouseButtonEvent}.
*/
public static final class Builder {
private @Action int mAction = ACTION_UNKNOWN;
private @Button int mButtonCode = -1;
+ private long mEventTimeNanos = 0L;
/**
* Creates a {@link VirtualMouseButtonEvent} object with the current builder configuration.
@@ -133,7 +151,7 @@
throw new IllegalArgumentException(
"Cannot build virtual mouse button event with unset fields");
}
- return new VirtualMouseButtonEvent(mAction, mButtonCode);
+ return new VirtualMouseButtonEvent(mAction, mButtonCode, mEventTimeNanos);
}
/**
@@ -165,6 +183,23 @@
mAction = action;
return this;
}
+
+ /**
+ * Sets the time (in nanoseconds) when this specific event was generated. This may be
+ * obtained from {@link SystemClock#uptimeMillis()} (with nanosecond precision instead of
+ * millisecond), but can be different depending on the use case.
+ * This field is optional and can be omitted.
+ *
+ * @return this builder, to allow for chaining of calls
+ * @see InputEvent#getEventTime()
+ */
+ public @NonNull Builder setEventTimeNanos(long eventTimeNanos) {
+ if (eventTimeNanos < 0L) {
+ throw new IllegalArgumentException("Event time cannot be negative");
+ }
+ this.mEventTimeNanos = eventTimeNanos;
+ return this;
+ }
}
public static final @NonNull Parcelable.Creator<VirtualMouseButtonEvent> CREATOR =
diff --git a/core/java/android/hardware/input/VirtualMouseRelativeEvent.java b/core/java/android/hardware/input/VirtualMouseRelativeEvent.java
index 65ed1f2..e6ad118 100644
--- a/core/java/android/hardware/input/VirtualMouseRelativeEvent.java
+++ b/core/java/android/hardware/input/VirtualMouseRelativeEvent.java
@@ -20,6 +20,8 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
+import android.view.InputEvent;
/**
* An event describing a mouse movement interaction originating from a remote device.
@@ -33,21 +35,25 @@
private final float mRelativeX;
private final float mRelativeY;
+ private final long mEventTimeNanos;
- private VirtualMouseRelativeEvent(float relativeX, float relativeY) {
+ private VirtualMouseRelativeEvent(float relativeX, float relativeY, long eventTimeNanos) {
mRelativeX = relativeX;
mRelativeY = relativeY;
+ mEventTimeNanos = eventTimeNanos;
}
private VirtualMouseRelativeEvent(@NonNull Parcel parcel) {
mRelativeX = parcel.readFloat();
mRelativeY = parcel.readFloat();
+ mEventTimeNanos = parcel.readLong();
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
parcel.writeFloat(mRelativeX);
parcel.writeFloat(mRelativeY);
+ parcel.writeLong(mEventTimeNanos);
}
@Override
@@ -70,19 +76,30 @@
}
/**
+ * Returns the time this event occurred, in the {@link SystemClock#uptimeMillis()} time base but
+ * with nanosecond (instead of millisecond) precision.
+ *
+ * @see InputEvent#getEventTime()
+ */
+ public long getEventTimeNanos() {
+ return mEventTimeNanos;
+ }
+
+ /**
* Builder for {@link VirtualMouseRelativeEvent}.
*/
public static final class Builder {
private float mRelativeX;
private float mRelativeY;
+ private long mEventTimeNanos = 0L;
/**
* Creates a {@link VirtualMouseRelativeEvent} object with the current builder
* configuration.
*/
public @NonNull VirtualMouseRelativeEvent build() {
- return new VirtualMouseRelativeEvent(mRelativeX, mRelativeY);
+ return new VirtualMouseRelativeEvent(mRelativeX, mRelativeY, mEventTimeNanos);
}
/**
@@ -104,6 +121,23 @@
mRelativeY = relativeY;
return this;
}
+
+ /**
+ * Sets the time (in nanoseconds) when this specific event was generated. This may be
+ * obtained from {@link SystemClock#uptimeMillis()} (with nanosecond precision instead of
+ * millisecond), but can be different depending on the use case.
+ * This field is optional and can be omitted.
+ *
+ * @return this builder, to allow for chaining of calls
+ * @see InputEvent#getEventTime()
+ */
+ public @NonNull Builder setEventTimeNanos(long eventTimeNanos) {
+ if (eventTimeNanos < 0L) {
+ throw new IllegalArgumentException("Event time cannot be negative");
+ }
+ this.mEventTimeNanos = eventTimeNanos;
+ return this;
+ }
}
public static final @NonNull Parcelable.Creator<VirtualMouseRelativeEvent> CREATOR =
diff --git a/core/java/android/hardware/input/VirtualMouseScrollEvent.java b/core/java/android/hardware/input/VirtualMouseScrollEvent.java
index 1723259..4d0a157 100644
--- a/core/java/android/hardware/input/VirtualMouseScrollEvent.java
+++ b/core/java/android/hardware/input/VirtualMouseScrollEvent.java
@@ -21,6 +21,8 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
+import android.view.InputEvent;
import com.android.internal.util.Preconditions;
@@ -36,21 +38,26 @@
private final float mXAxisMovement;
private final float mYAxisMovement;
+ private final long mEventTimeNanos;
- private VirtualMouseScrollEvent(float xAxisMovement, float yAxisMovement) {
+ private VirtualMouseScrollEvent(float xAxisMovement, float yAxisMovement,
+ long eventTimeNanos) {
mXAxisMovement = xAxisMovement;
mYAxisMovement = yAxisMovement;
+ mEventTimeNanos = eventTimeNanos;
}
private VirtualMouseScrollEvent(@NonNull Parcel parcel) {
mXAxisMovement = parcel.readFloat();
mYAxisMovement = parcel.readFloat();
+ mEventTimeNanos = parcel.readLong();
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
parcel.writeFloat(mXAxisMovement);
parcel.writeFloat(mYAxisMovement);
+ parcel.writeLong(mEventTimeNanos);
}
@Override
@@ -75,18 +82,29 @@
}
/**
+ * Returns the time this event occurred, in the {@link SystemClock#uptimeMillis()} time base but
+ * with nanosecond (instead of millisecond) precision.
+ *
+ * @see InputEvent#getEventTime()
+ */
+ public long getEventTimeNanos() {
+ return mEventTimeNanos;
+ }
+
+ /**
* Builder for {@link VirtualMouseScrollEvent}.
*/
public static final class Builder {
private float mXAxisMovement;
private float mYAxisMovement;
+ private long mEventTimeNanos = 0L;
/**
* Creates a {@link VirtualMouseScrollEvent} object with the current builder configuration.
*/
public @NonNull VirtualMouseScrollEvent build() {
- return new VirtualMouseScrollEvent(mXAxisMovement, mYAxisMovement);
+ return new VirtualMouseScrollEvent(mXAxisMovement, mYAxisMovement, mEventTimeNanos);
}
/**
@@ -114,6 +132,23 @@
mYAxisMovement = yAxisMovement;
return this;
}
+
+ /**
+ * Sets the time (in nanoseconds) when this specific event was generated. This may be
+ * obtained from {@link SystemClock#uptimeMillis()} (with nanosecond precision instead of
+ * millisecond), but can be different depending on the use case.
+ * This field is optional and can be omitted.
+ *
+ * @return this builder, to allow for chaining of calls
+ * @see InputEvent#getEventTime()
+ */
+ public @NonNull Builder setEventTimeNanos(long eventTimeNanos) {
+ if (eventTimeNanos < 0L) {
+ throw new IllegalArgumentException("Event time cannot be negative");
+ }
+ mEventTimeNanos = eventTimeNanos;
+ return this;
+ }
}
public static final @NonNull Parcelable.Creator<VirtualMouseScrollEvent> CREATOR =
diff --git a/core/java/android/hardware/input/VirtualTouchEvent.java b/core/java/android/hardware/input/VirtualTouchEvent.java
index a2bb382..73da5d9 100644
--- a/core/java/android/hardware/input/VirtualTouchEvent.java
+++ b/core/java/android/hardware/input/VirtualTouchEvent.java
@@ -23,6 +23,8 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
+import android.view.InputEvent;
import android.view.MotionEvent;
import java.lang.annotation.Retention;
@@ -94,9 +96,10 @@
private final float mY;
private final float mPressure;
private final float mMajorAxisSize;
+ private final long mEventTimeNanos;
private VirtualTouchEvent(int pointerId, @ToolType int toolType, @Action int action,
- float x, float y, float pressure, float majorAxisSize) {
+ float x, float y, float pressure, float majorAxisSize, long eventTimeNanos) {
mPointerId = pointerId;
mToolType = toolType;
mAction = action;
@@ -104,6 +107,7 @@
mY = y;
mPressure = pressure;
mMajorAxisSize = majorAxisSize;
+ mEventTimeNanos = eventTimeNanos;
}
private VirtualTouchEvent(@NonNull Parcel parcel) {
@@ -114,6 +118,7 @@
mY = parcel.readFloat();
mPressure = parcel.readFloat();
mMajorAxisSize = parcel.readFloat();
+ mEventTimeNanos = parcel.readLong();
}
@Override
@@ -125,6 +130,7 @@
dest.writeFloat(mY);
dest.writeFloat(mPressure);
dest.writeFloat(mMajorAxisSize);
+ dest.writeLong(mEventTimeNanos);
}
@Override
@@ -182,6 +188,16 @@
}
/**
+ * Returns the time this event occurred, in the {@link SystemClock#uptimeMillis()} time base but
+ * with nanosecond (instead of millisecond) precision.
+ *
+ * @see InputEvent#getEventTime()
+ */
+ public long getEventTimeNanos() {
+ return mEventTimeNanos;
+ }
+
+ /**
* Builder for {@link VirtualTouchEvent}.
*/
public static final class Builder {
@@ -193,6 +209,7 @@
private float mY = Float.NaN;
private float mPressure = Float.NaN;
private float mMajorAxisSize = Float.NaN;
+ private long mEventTimeNanos = 0L;
/**
* Creates a {@link VirtualTouchEvent} object with the current builder configuration.
@@ -213,7 +230,7 @@
"ACTION_CANCEL and TOOL_TYPE_PALM must always appear together");
}
return new VirtualTouchEvent(mPointerId, mToolType, mAction, mX, mY, mPressure,
- mMajorAxisSize);
+ mMajorAxisSize, mEventTimeNanos);
}
/**
@@ -317,6 +334,23 @@
mMajorAxisSize = majorAxisSize;
return this;
}
+
+ /**
+ * Sets the time (in nanoseconds) when this specific event was generated. This may be
+ * obtained from {@link SystemClock#uptimeMillis()} (with nanosecond precision instead of
+ * millisecond), but can be different depending on the use case.
+ * This field is optional and can be omitted.
+ *
+ * @return this builder, to allow for chaining of calls
+ * @see InputEvent#getEventTime()
+ */
+ public @NonNull Builder setEventTimeNanos(long eventTimeNanos) {
+ if (eventTimeNanos < 0L) {
+ throw new IllegalArgumentException("Event time cannot be negative");
+ }
+ mEventTimeNanos = eventTimeNanos;
+ return this;
+ }
}
public static final @NonNull Parcelable.Creator<VirtualTouchEvent> CREATOR =
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index cbbd16b..fa16e16 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -42,6 +42,7 @@
import android.media.AudioFormat;
import android.media.permission.Identity;
import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.ISoundTriggerInjection;
import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.os.Build;
@@ -77,9 +78,11 @@
}
/**
+ * Model architecture associated with a fake STHAL which can be injected.
+ * Used for testing purposes.
* @hide
*/
- public static final String FAKE_HAL_ARCH = "injection";
+ public static final String FAKE_HAL_ARCH = ISoundTriggerInjection.FAKE_HAL_ARCH;
/**
* Status code used when the operation succeeded
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 89b768d..5137bc1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11849,7 +11849,13 @@
/**
* Value to specify if the device's UTC system clock should be set automatically, e.g. using
- * telephony signals like NITZ, or other sources like GNSS or NTP. 1=yes, 0=no (manual)
+ * telephony signals like NITZ, or other sources like GNSS or NTP.
+ *
+ * <p>Prefer {@link android.app.time.TimeManager} API calls to determine the state of
+ * automatic time detection instead of directly observing this setting as it may be ignored
+ * by the time_detector service under various conditions.
+ *
+ * <p>1=yes, 0=no (manual)
*/
@Readable
public static final String AUTO_TIME = "auto_time";
@@ -11857,12 +11863,35 @@
/**
* Value to specify if the device's time zone system property should be set automatically,
* e.g. using telephony signals like MCC and NITZ, or other mechanisms like the location.
- * 1=yes, 0=no (manual).
+ *
+ * <p>Prefer {@link android.app.time.TimeManager} API calls to determine the state of
+ * automatic time zone detection instead of directly observing this setting as it may be
+ * ignored by the time_zone_detector service under various conditions.
+ *
+ * <p>1=yes, 0=no (manual).
*/
@Readable
public static final String AUTO_TIME_ZONE = "auto_time_zone";
/**
+ * Records whether an explicit preference for {@link #AUTO_TIME_ZONE} has been expressed
+ * instead of the current value being the default. This value is used to tell if the {@link
+ * #AUTO_TIME_ZONE} value can be influenced by experiment flags that alter the setting's
+ * value for internal testers: once the user indicates a preference they leave the
+ * experiment, only users that are still using the default will be affected by the flag.
+ *
+ * <p>Since {@link #AUTO_TIME_ZONE} can be altered by components besides the system server,
+ * and not just via the time_zone_detector logic that sets this value, this isn't guaranteed
+ * to be set when the device diverges from the default in all cases. Important AOSP system
+ * components like SettingsUI do use the time_zone_detector APIs.
+ *
+ * <p>1="has been set explicitly"
+ *
+ * @hide
+ */
+ public static final String AUTO_TIME_ZONE_EXPLICIT = "auto_time_zone_explicit";
+
+ /**
* URI for the car dock "in" event sound.
* @hide
*/
diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
index 8069414..47b75d1 100644
--- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java
+++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java
@@ -163,28 +163,12 @@
private static boolean isSystemProviderWithValidPermission(
ServiceInfo serviceInfo, Context context) {
- requireNonNull(context, "context must not be null");
-
- final String permission = Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE;
- try {
- ApplicationInfo appInfo =
- context.getPackageManager()
- .getApplicationInfo(
- serviceInfo.packageName,
- PackageManager.ApplicationInfoFlags.of(
- PackageManager.MATCH_SYSTEM_ONLY));
- if (appInfo != null
- && context.checkPermission(permission, /* pid= */ -1, appInfo.uid)
- == PackageManager.PERMISSION_GRANTED) {
- Slog.i(TAG, "SYS permission granted for: " + serviceInfo.packageName);
- return true;
- } else {
- Slog.i(TAG, "SYS permission failed for: " + serviceInfo.packageName);
- }
- } catch (PackageManager.NameNotFoundException e) {
- Slog.e(TAG, "Error getting info for " + serviceInfo + ": " + e);
+ if (context == null) {
+ Slog.w(TAG, "Context is null in isSystemProviderWithValidPermission");
+ return false;
}
- return false;
+ return PermissionUtils.hasPermission(context, serviceInfo.packageName,
+ Manifest.permission.PROVIDE_DEFAULT_ENABLED_CREDENTIAL_SERVICE);
}
private static boolean isValidSystemProvider(
diff --git a/core/java/android/service/credentials/PermissionUtils.java b/core/java/android/service/credentials/PermissionUtils.java
new file mode 100644
index 0000000..c8bb202
--- /dev/null
+++ b/core/java/android/service/credentials/PermissionUtils.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.credentials;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+
+/**
+ * Utils for checking permissions, or any other permission related function
+ *
+ * @hide
+ */
+public class PermissionUtils {
+ //TODO(274838409): Move all CredentialManagerService permission checks here
+
+ /** Checks whether the given package name hold the given permission **/
+ public static boolean hasPermission(Context context, String packageName, String permission) {
+ try {
+ ApplicationInfo appInfo =
+ context.getPackageManager()
+ .getApplicationInfo(
+ packageName,
+ PackageManager.ApplicationInfoFlags.of(
+ PackageManager.MATCH_SYSTEM_ONLY));
+ if (appInfo != null
+ && context.checkPermission(permission, /* pid= */ -1, appInfo.uid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ return false;
+ }
+}
+
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 61864d77..e81aecb 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -776,7 +776,7 @@
* Each gamepad or joystick is given a unique, positive controller number when initially
* configured by the system. This number may change due to events such as device disconnects /
* reconnects or user initiated reassignment. Any change in number will trigger an event that
- * can be observed by registering an {@link InputManager.InputDeviceListener}.
+ * can be observed by registering an {@link InputManagerGlobal.InputDeviceListener}.
* </p>
* <p>
* All input devices which are not gamepads or joysticks will be assigned a controller number
@@ -981,7 +981,7 @@
* generating the keycode given by the corresponding value at the same index in the keys array.
*/
public boolean[] hasKeys(int... keys) {
- return InputManager.getInstance().deviceHasKeys(mId, keys);
+ return InputManagerGlobal.getInstance().deviceHasKeys(mId, keys);
}
/**
@@ -1028,7 +1028,8 @@
* {@link InputDevice#SOURCE_KEYBOARD} or the requested mapping cannot be determined.
*/
public int getKeyCodeForKeyLocation(int locationKeyCode) {
- return InputManager.getInstance().getKeyCodeForKeyLocation(mId, locationKeyCode);
+ return InputManagerGlobal.getInstance()
+ .getKeyCodeForKeyLocation(mId, locationKeyCode);
}
/**
@@ -1109,9 +1110,11 @@
@RequiresPermission(Manifest.permission.BLUETOOTH)
@Nullable
public String getBluetoothAddress() {
- // We query the address via a separate InputManager API instead of pre-populating it in
- // this class to avoid leaking it to apps that do not have sufficient permissions.
- return InputManager.getInstance().getInputDeviceBluetoothAddress(mId);
+ // We query the address via a separate InputManagerGlobal API
+ // instead of pre-populating it in this class to avoid
+ // leaking it to apps that do not have sufficient permissions.
+ return InputManagerGlobal.getInstance()
+ .getInputDeviceBluetoothAddress(mId);
}
/**
@@ -1132,7 +1135,8 @@
synchronized (mMotionRanges) {
if (mVibrator == null) {
if (mHasVibrator) {
- mVibrator = InputManager.getInstance().getInputDeviceVibrator(mId,
+ mVibrator = InputManagerGlobal.getInstance()
+ .getInputDeviceVibrator(mId,
VIBRATOR_ID_ALL);
} else {
mVibrator = NullVibrator.getInstance();
@@ -1154,7 +1158,8 @@
public VibratorManager getVibratorManager() {
synchronized (mMotionRanges) {
if (mVibratorManager == null) {
- mVibratorManager = InputManager.getInstance().getInputDeviceVibratorManager(mId);
+ mVibratorManager = InputManagerGlobal.getInstance()
+ .getInputDeviceVibratorManager(mId);
}
}
return mVibratorManager;
@@ -1170,7 +1175,8 @@
*/
@NonNull
public BatteryState getBatteryState() {
- return InputManager.getInstance().getInputDeviceBatteryState(mId, mHasBattery);
+ return InputManagerGlobal.getInstance()
+ .getInputDeviceBatteryState(mId, mHasBattery);
}
/**
@@ -1206,7 +1212,8 @@
public SensorManager getSensorManager() {
synchronized (mMotionRanges) {
if (mSensorManager == null) {
- mSensorManager = InputManager.getInstance().getInputDeviceSensorManager(mId);
+ mSensorManager = InputManagerGlobal.getInstance()
+ .getInputDeviceSensorManager(mId);
}
}
return mSensorManager;
@@ -1217,7 +1224,7 @@
* @return Whether the input device is enabled.
*/
public boolean isEnabled() {
- return InputManager.getInstance().isInputDeviceEnabled(mId);
+ return InputManagerGlobal.getInstance().isInputDeviceEnabled(mId);
}
/**
@@ -1228,7 +1235,7 @@
@RequiresPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE)
@TestApi
public void enable() {
- InputManager.getInstance().enableInputDevice(mId);
+ InputManagerGlobal.getInstance().enableInputDevice(mId);
}
/**
@@ -1239,7 +1246,7 @@
@RequiresPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE)
@TestApi
public void disable() {
- InputManager.getInstance().disableInputDevice(mId);
+ InputManagerGlobal.getInstance().disableInputDevice(mId);
}
/**
@@ -1274,7 +1281,7 @@
* @hide
*/
public void setPointerType(int pointerType) {
- InputManager.getInstance().setPointerIconType(pointerType);
+ InputManagerGlobal.getInstance().setPointerIconType(pointerType);
}
/**
@@ -1283,7 +1290,7 @@
* @hide
*/
public void setCustomPointerIcon(PointerIcon icon) {
- InputManager.getInstance().setCustomPointerIcon(icon);
+ InputManagerGlobal.getInstance().setCustomPointerIcon(icon);
}
/**
@@ -1301,7 +1308,7 @@
*
* @return the supported USI version, or null if the device does not support USI
* @see <a href="https://universalstylus.org">Universal Stylus Initiative</a>
- * @see InputManager#getHostUsiVersion(int)
+ * @see InputManagerGlobal#getHostUsiVersion(int)
* @hide
*/
@Nullable
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b46a68c..cdea97c 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,7 +33,6 @@
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RenderNode;
@@ -851,10 +850,14 @@
}
mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
- if (mViewVisibility) {
- surfaceUpdateTransaction.show(mSurfaceControl);
- } else {
- surfaceUpdateTransaction.hide(mSurfaceControl);
+ // Only control visibility if we're not hardware-accelerated. Otherwise we'll
+ // let renderthread drive since offscreen SurfaceControls should not be visible.
+ if (!isHardwareAccelerated()) {
+ if (mViewVisibility) {
+ surfaceUpdateTransaction.show(mSurfaceControl);
+ } else {
+ surfaceUpdateTransaction.hide(mSurfaceControl);
+ }
}
updateBackgroundVisibility(surfaceUpdateTransaction);
@@ -1417,12 +1420,10 @@
}
private final Rect mRTLastReportedPosition = new Rect();
- private final Point mRTLastReportedSurfaceSize = new Point();
private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
private final int mRtSurfaceWidth;
private final int mRtSurfaceHeight;
- private boolean mRtFirst = true;
private final SurfaceControl.Transaction mPositionChangedTransaction =
new SurfaceControl.Transaction();
@@ -1433,15 +1434,6 @@
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
- if (!mRtFirst && (mRTLastReportedPosition.left == left
- && mRTLastReportedPosition.top == top
- && mRTLastReportedPosition.right == right
- && mRTLastReportedPosition.bottom == bottom
- && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
- && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight)) {
- return;
- }
- mRtFirst = false;
try {
if (DEBUG_POSITION) {
Log.d(TAG, String.format(
@@ -1452,8 +1444,8 @@
}
synchronized (mSurfaceControlLock) {
if (mSurfaceControl == null) return;
+
mRTLastReportedPosition.set(left, top, right, bottom);
- mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
onSetSurfacePositionAndScale(mPositionChangedTransaction, mSurfaceControl,
mRTLastReportedPosition.left /*positionLeft*/,
mRTLastReportedPosition.top /*positionTop*/,
@@ -1461,10 +1453,8 @@
/ (float) mRtSurfaceWidth /*postScaleX*/,
mRTLastReportedPosition.height()
/ (float) mRtSurfaceHeight /*postScaleY*/);
- if (mViewVisibility) {
- // b/131239825
- mPositionChangedTransaction.show(mSurfaceControl);
- }
+
+ mPositionChangedTransaction.show(mSurfaceControl);
}
applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
} catch (Exception ex) {
@@ -1490,7 +1480,6 @@
System.identityHashCode(this), frameNumber));
}
mRTLastReportedPosition.setEmpty();
- mRTLastReportedSurfaceSize.set(-1, -1);
// positionLost can be called while UI thread is un-paused.
synchronized (mSurfaceControlLock) {
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index ced2722..77de272 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -40,6 +40,8 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Arrays;
import java.util.WeakHashMap;
@@ -280,6 +282,92 @@
return charSequence;
}
+ /**
+ * Ensures contrast on color spans against a background color.
+ * Note that any full-length color spans will be removed instead of being contrasted.
+ *
+ * @param charSequence the charSequence on which the spans are
+ * @param background the background color to ensure the contrast against
+ * @return the contrasted charSequence
+ */
+ public static CharSequence ensureColorSpanContrast(CharSequence charSequence,
+ int background) {
+ if (charSequence == null) {
+ return charSequence;
+ }
+ if (charSequence instanceof Spanned) {
+ Spanned ss = (Spanned) charSequence;
+ Object[] spans = ss.getSpans(0, ss.length(), Object.class);
+ SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
+ for (Object span : spans) {
+ Object resultSpan = span;
+ int spanStart = ss.getSpanStart(span);
+ int spanEnd = ss.getSpanEnd(span);
+ boolean fullLength = (spanEnd - spanStart) == charSequence.length();
+ if (resultSpan instanceof CharacterStyle) {
+ resultSpan = ((CharacterStyle) span).getUnderlying();
+ }
+ if (resultSpan instanceof TextAppearanceSpan) {
+ TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
+ ColorStateList textColor = originalSpan.getTextColor();
+ if (textColor != null) {
+ if (fullLength) {
+ // Let's drop the color from the span
+ textColor = null;
+ } else {
+ int[] colors = textColor.getColors();
+ int[] newColors = new int[colors.length];
+ for (int i = 0; i < newColors.length; i++) {
+ boolean isBgDark = isColorDark(background);
+ newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
+ colors[i], background, isBgDark);
+ }
+ textColor = new ColorStateList(textColor.getStates().clone(),
+ newColors);
+ }
+ resultSpan = new TextAppearanceSpan(
+ originalSpan.getFamily(),
+ originalSpan.getTextStyle(),
+ originalSpan.getTextSize(),
+ textColor,
+ originalSpan.getLinkTextColor());
+ }
+ } else if (resultSpan instanceof ForegroundColorSpan) {
+ if (fullLength) {
+ resultSpan = null;
+ } else {
+ ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
+ int foregroundColor = originalSpan.getForegroundColor();
+ boolean isBgDark = isColorDark(background);
+ foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
+ foregroundColor, background, isBgDark);
+ resultSpan = new ForegroundColorSpan(foregroundColor);
+ }
+ } else {
+ resultSpan = span;
+ }
+ if (resultSpan != null) {
+ builder.setSpan(resultSpan, spanStart, spanEnd, ss.getSpanFlags(span));
+ }
+ }
+ return builder;
+ }
+ return charSequence;
+ }
+
+ /**
+ * Determines if the color is light or dark. Specifically, this is using the same metric as
+ * {@link ContrastColorUtil#resolvePrimaryColor(Context, int, boolean)} and peers so that
+ * the direction of color shift is consistent.
+ *
+ * @param color the color to check
+ * @return true if the color has higher contrast with white than black
+ */
+ public static boolean isColorDark(int color) {
+ // as per shouldUseDark(), this uses the color contrast midpoint.
+ return calculateLuminance(color) <= 0.17912878474;
+ }
+
private int processColor(int color) {
return Color.argb(Color.alpha(color),
255 - Color.red(color),
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 3c06755..c144503 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -35,6 +35,7 @@
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_BACK_ARROW;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_SELECTION_TOOLBAR;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION;
+import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_SWITCH_DISPLAY_UNFOLD;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS;
@@ -205,6 +206,15 @@
*/
public static final int ACTION_REQUEST_IME_HIDDEN = 21;
+ /**
+ * Time it takes to load the animation frames in smart space doorbell card.
+ * It measures the duration from the images uris are passed into the view
+ * to all the frames are loaded.
+ * <p/>
+ * A long latency makes the doorbell animation looks janky until all the frames are loaded.
+ */
+ public static final int ACTION_SMARTSPACE_DOORBELL = 22;
+
private static final int[] ACTIONS_ALL = {
ACTION_EXPAND_PANEL,
ACTION_TOGGLE_RECENTS,
@@ -228,6 +238,7 @@
ACTION_SHOW_VOICE_INTERACTION,
ACTION_REQUEST_IME_SHOWN,
ACTION_REQUEST_IME_HIDDEN,
+ ACTION_SMARTSPACE_DOORBELL,
};
/** @hide */
@@ -254,6 +265,7 @@
ACTION_SHOW_VOICE_INTERACTION,
ACTION_REQUEST_IME_SHOWN,
ACTION_REQUEST_IME_HIDDEN,
+ ACTION_SMARTSPACE_DOORBELL,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
@@ -283,6 +295,7 @@
UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHOW_VOICE_INTERACTION,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_SHOWN,
UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN,
+ UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL,
};
private final Object mLock = new Object();
@@ -407,6 +420,8 @@
return "ACTION_REQUEST_IME_SHOWN";
case UIACTION_LATENCY_REPORTED__ACTION__ACTION_REQUEST_IME_HIDDEN:
return "ACTION_REQUEST_IME_HIDDEN";
+ case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SMARTSPACE_DOORBELL:
+ return "ACTION_SMARTSPACE_DOORBELL";
default:
throw new IllegalArgumentException("Invalid action");
}
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 3191e23..302d2e7 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -361,13 +361,15 @@
// same padding on bottom and at end
int paddingBottom = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end);
- height = mEmphasizedHeight;
int buttonPaddingInternal = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.button_inset_vertical_material);
setPaddingRelative(getPaddingStart(),
paddingTop - buttonPaddingInternal,
getPaddingEnd(),
paddingBottom - buttonPaddingInternal);
+
+ setMinimumHeight(mEmphasizedHeight);
+ height = ViewGroup.LayoutParams.WRAP_CONTENT;
} else {
setPaddingRelative(getPaddingStart(),
mDefaultPaddingTop,
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 9e92542..a2205eb 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -94,6 +94,7 @@
jfieldID mScreenWidthDpOffset;
jfieldID mScreenHeightDpOffset;
jfieldID mScreenLayoutOffset;
+ jfieldID mUiMode;
} gConfigurationOffsets;
static struct arraymap_offsets_t {
@@ -1030,10 +1031,11 @@
env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
env->SetIntField(result, gConfigurationOffsets.mScreenLayoutOffset, config.screenLayout);
+ env->SetIntField(result, gConfigurationOffsets.mUiMode, config.uiMode);
return result;
}
-static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+static jobjectArray GetSizeAndUiModeConfigurations(JNIEnv* env, jlong ptr) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
auto configurations = assetmanager->GetResourceConfigurations(true /*exclude_system*/,
false /*exclude_mipmap*/);
@@ -1060,6 +1062,14 @@
return array;
}
+static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+ return GetSizeAndUiModeConfigurations(env, ptr);
+}
+
+static jobjectArray NativeGetSizeAndUiModeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+ return GetSizeAndUiModeConfigurations(env, ptr);
+}
+
static jintArray NativeAttributeResolutionStack(
JNIEnv* env, jclass /*clazz*/, jlong ptr,
jlong theme_ptr, jint xml_style_res,
@@ -1494,6 +1504,8 @@
{"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
{"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
(void*)NativeGetSizeConfigurations},
+ {"nativeGetSizeAndUiModeConfigurations", "(J)[Landroid/content/res/Configuration;",
+ (void*)NativeGetSizeAndUiModeConfigurations},
// Style attribute related methods.
{"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
@@ -1572,6 +1584,7 @@
GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
gConfigurationOffsets.mScreenLayoutOffset =
GetFieldIDOrDie(env, configurationClass, "screenLayout", "I");
+ gConfigurationOffsets.mUiMode = GetFieldIDOrDie(env, configurationClass, "uiMode", "I");
jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap");
gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass);
diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml
index c024dbe..da515d7 100644
--- a/core/res/res/layout/notification_material_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -19,7 +19,8 @@
style="@android:style/NotificationAction"
android:id="@+id/action0"
android:layout_width="wrap_content"
- android:layout_height="48dp"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
android:layout_gravity="center"
android:gravity="start|center_vertical"
android:layout_marginStart="4dp"
diff --git a/core/res/res/layout/notification_material_action_emphasized.xml b/core/res/res/layout/notification_material_action_emphasized.xml
index ea84185..ac90948 100644
--- a/core/res/res/layout/notification_material_action_emphasized.xml
+++ b/core/res/res/layout/notification_material_action_emphasized.xml
@@ -19,7 +19,8 @@
style="@style/NotificationEmphasizedAction"
android:id="@+id/action0"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_action_emphasized_height"
android:layout_marginStart="12dp"
android:drawablePadding="6dp"
android:gravity="center"
diff --git a/core/res/res/layout/notification_material_action_emphasized_tombstone.xml b/core/res/res/layout/notification_material_action_emphasized_tombstone.xml
index 60f10db..16ea70c 100644
--- a/core/res/res/layout/notification_material_action_emphasized_tombstone.xml
+++ b/core/res/res/layout/notification_material_action_emphasized_tombstone.xml
@@ -20,7 +20,8 @@
style="@style/NotificationEmphasizedAction"
android:id="@+id/action0"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_action_emphasized_height"
android:layout_marginStart="12dp"
android:drawablePadding="6dp"
android:enabled="false"
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 7aef82a..057270a 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -36,7 +36,8 @@
android:id="@+id/actions"
android:layout_width="0dp"
android:layout_weight="1"
- android:layout_height="@dimen/notification_action_list_height"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_action_list_height"
android:orientation="horizontal"
android:gravity="center_vertical"
android:visibility="gone"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 262fb6f..42e5188 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-oproepe"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-fi-oproep"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Af"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Bel oor Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Bel oor mobiele netwerk"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruik tans albei skerms om inhoud te wys"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Toestel is te warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dubbelskerm is nie beskikbaar nie omdat jou foon tans te warm word"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is nie beskikbaar nie"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is nie beskikbaar nie omdat Batterybespaarder aan is. Jy kan dit in Instellings afskakel."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Gaan na Instellings"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Skakel af"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> is opgestel"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Sleutelborduitleg is gestel op <xliff:g id="LAYOUT_1">%s</xliff:g>. Tik om te verander."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index aa01323..26f99bf 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2325,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> ይዘትን ለማሳየት ሁለቱንም ማሳያዎች እየተጠቀመ ነው"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"መሣሪያ በጣም ሞቋል"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ስልክዎ በጣም እየሞቀ ስለሆነ ባለሁለት ማያ ገጽ አይገኝም"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen አይገኝም"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"የባትሪ ቆጣቢ ስለበራ Dual Screen አይገኝም። ይህን በቅንብሮች ውስጥ ሊያጠፉት ይችላሉ።"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ወደ ቅንብሮች ሂድ"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"አጥፋ"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ተዋቅሯል"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"የቁልፍ ሰሌዳ ወደ <xliff:g id="LAYOUT_1">%s</xliff:g> ተቀናብሯል። ለመለወጥ መታ ያድርጉ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index ce47a3e..7335043 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -144,8 +144,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"الاتصال عبر WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"مكالمة عبر Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"غير مفعّل"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"الاتصال عبر Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"الاتصال عبر شبكة الجوّال"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 07a578b..9be6860 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"ৱাই-ফাই"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"ৱাই-ফাই কলিং"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"ৱাই-ফাই কল"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"অফ হৈ আছে"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"ৱাই-ফাইৰ জৰিয়তে কল কৰক"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ম’বাইল নেটৱৰ্কৰ জৰিয়তে কল কৰক"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ সমল দেখুৱাবলৈ দুয়োখন ডিছপ্লে’ ব্যৱহাৰ কৰি আছে"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ডিভাইচটো অতি বেছি গৰম হৈছে"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"আপোনাৰ ফ’নটো অতি বেছি গৰম হোৱাৰ বাবে ডুৱেল স্ক্ৰীন উপলব্ধ নহয়"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen উপলব্ধ নহয়"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"বেটাৰী সঞ্চয়কাৰী অন হৈ থকাৰ কাৰণে Dual Screen সুবিধাটো উপলব্ধ নহয়। আপুনি ছেটিঙত এই সুবিধাটো অফ কৰিব পাৰে।"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ছেটিঙলৈ যাওক"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"অফ কৰক"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> কনফিগাৰ কৰা হৈছে"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"কীব’ৰ্ডৰ লে’আউট <xliff:g id="LAYOUT_1">%s</xliff:g> হিচাপে ছেট কৰা হৈছে। সলনি কৰিবলৈ টিপক।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index a843c7c..94ceba5 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WiFi Zəngi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WiFi zəngi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Deaktiv"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi ilə zəng edin"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Mobil şəbəkə ilə zəng edin"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> məzmunu göstərmək üçün hər iki displeydən istifadə edir"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Cihaz çox isinib"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Telefonunuz çox isindiyi üçün İkili Ekran əlçatan deyil"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen əlçatan deyil"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Enerjiyə Qənaət aktiv olduğu üçün Dual Screen əlçatan deyil. Ayarlarda deaktiv edə bilərsiniz."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ayarlara keçin"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Deaktiv edin"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> konfiqurasiya edilib"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Klaviatura düzəni <xliff:g id="LAYOUT_1">%s</xliff:g> kimi ayarlanıb. Dəyişmək üçün toxunun."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 7b99842..fa6991f 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"WiFi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Pozivanje preko WiFi-a"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Poziv preko WiFi-ja"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Isključeno"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Pozivanje preko WiFi-a"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Poziv preko mobilne mreže"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> koristi oba ekrana za prikazivanje sadržaja"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Uređaj je previše zagrejan"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dvojni ekran je nedostupan jer je telefon previše zagrejan"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen nije dostupan"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen nije dostupan zato što je Ušteda baterije uključena. To možete da isključite u podešavanjima."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Idi u Podešavanja"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Isključi"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Uređaj <xliff:g id="DEVICE_NAME">%s</xliff:g> je konfigurisan"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Raspored tastature je podešen na <xliff:g id="LAYOUT_1">%s</xliff:g>. Dodirnite da biste to promenili."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 080bf2c..3037acb 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -142,8 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-тэлефанія"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWi-Fi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Выклік праз Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Выкл."</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Выклікаць праз Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Выклікаць праз мабільную сетку"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b2abe40..a70d59f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Обаждания през Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Обаждане през Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Изключено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Обаждане през Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Обаждане през мобилна мрежа"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Приложението <xliff:g id="APP_NAME">%1$s</xliff:g> използва и двата екрана, за да показва съдържание"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Устройството е твърде топло"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Функцията за двоен екран не е налице, защото телефонът ви е твърде топъл"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функцията Dual Screen не е налице"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функцията Dual Screen не е налице, защото режимът за запазване на батерията е включен. Можете да го изключите от настройките."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Към настройките"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Изключване"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Устройството <xliff:g id="DEVICE_NAME">%s</xliff:g> е конфигурирано"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"За клавиатурната подредба е зададен <xliff:g id="LAYOUT_1">%s</xliff:g>. Докоснете за промяна."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 64448fd0..16cbc77 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"কন্টেন্ট দেখানোর জন্য <xliff:g id="APP_NAME">%1$s</xliff:g> দুটি ডিসপ্লে ব্যবহার করছে"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ডিভাইস খুব গরম হয়ে গেছে"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"আপনার ফোন খুব বেশি গরম হয়ে যাচ্ছে বলে \'ডুয়াল স্ক্রিন\' উপলভ্য নেই"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen উপলভ্য নেই"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"\'ব্যাটারি সেভার\' চালু করা আছে বলে Dual Screen ফিচারের সুবিধা উপলভ্য হবে না। আপনি সেটিংস থেকে এটি বন্ধ করতে পারবেন।"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"সেটিংসে যান"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"বন্ধ করুন"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> কনফিগার করা হয়েছে"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"কীবোর্ড লেআউট <xliff:g id="LAYOUT_1">%s</xliff:g>-এ সেট করা আছে। পরিবর্তন করতে ট্যাপ করুন।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 1a702aa..0b78d26 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -141,7 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"WiFi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Pozivanje putem WIFi-ja"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi poziv"</string>
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WiFi poziv"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Isključeno"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Poziv putem WiFi-ja"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Poziv putem mobilne mreže"</string>
@@ -2325,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> koristi oba ekrana za prikazivanje sadržaja"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Uređaj je previše zagrijan"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dupli ekran nije dostupan je se telefon previše zagrijava"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen nije dostupan"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen nije dostupan jer je Ušteda baterije uključena. To možete isključiti u Postavkama."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Idi u Postavke"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Isključi"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Uređaj <xliff:g id="DEVICE_NAME">%s</xliff:g> je konfiguriran"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Raspored tastature je postavljen na <xliff:g id="LAYOUT_1">%s</xliff:g>. Dodirnite da promijenite."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 1fe8f61..f08cb3a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi‑Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Trucades per Wi‑Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Trucada per Wifi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Desactivat"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Trucades per Wi‑Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Trucades per la xarxa mòbil"</string>
@@ -618,7 +617,7 @@
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string>
<string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilitza la biometria"</string>
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Fes servir la biometria o el bloqueig de pantalla"</string>
- <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que ets tu"</string>
+ <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la teva identitat"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilitza la teva biometria per continuar"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilitza la biometria o el bloqueig de pantalla per continuar"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maquinari biomètric no disponible"</string>
@@ -1238,7 +1237,7 @@
<string name="screen_compat_mode_scale" msgid="8627359598437527726">"Escala"</string>
<string name="screen_compat_mode_show" msgid="5080361367584709857">"Mostra sempre"</string>
<string name="screen_compat_mode_hint" msgid="4032272159093750908">"Torna a activar-ho a Configuració del sistema > Aplicacions > Baixades."</string>
- <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string>
+ <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de visualització actual i és possible que funcioni de manera inesperada."</string>
<string name="unsupported_display_size_show" msgid="980129850974919375">"Mostra sempre"</string>
<string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va crear per a una versió incompatible del sistema operatiu Android i pot funcionar de manera inesperada. És possible que hi hagi disponible una versió actualitzada de l\'aplicació."</string>
<string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Mostra sempre"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> està utilitzant les dues pantalles per mostrar contingut"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"El dispositiu està massa calent"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"La pantalla dual no està disponible perquè el telèfon està massa calent"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen no està disponible"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen no està disponible perquè la funció Estalvi de bateria està activada. Pots desactivar aquesta opció a Configuració."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ves a Configuració"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desactiva"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configurat"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Disseny del teclat definit en <xliff:g id="LAYOUT_1">%s</xliff:g>. Toca per canviar-ho."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0ed1dd8..d624345 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -142,8 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Volání přes WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Volání přes WiFi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Vypnuto"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Volání přes Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Volání přes mobilní síť"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3bb53d4..46269af 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-opkald"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi-opkald"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Fra"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Ring via Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Ring via mobilnetværk"</string>
@@ -1259,7 +1258,7 @@
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du har trykket på afbryderknappen, hvilket som regel slukker skærmen.\n\nPrøv at trykke let på knappen, mens du konfigurerer dit fingeraftryk."</string>
<string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Sluk skærmen for at afslutte konfigurationen"</string>
<string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Deaktiver"</string>
- <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vil du bekræfte dit fingeraftryk?"</string>
+ <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vil du verificere dit fingeraftryk?"</string>
<string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du har trykket på afbryderknappen, hvilket som regel slukker skærmen.\n\nPrøv at trykke let på knappen for at bekræfte dit fingeraftryk."</string>
<string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Sluk skærm"</string>
<string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"Fortsæt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8530755..afb2c73 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"WLAN"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WLAN-Telefonie"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WLAN-Anruf"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Aus"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Anruf über WLAN"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Über Mobilfunknetz anrufen"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> nutzt zum Anzeigen von Inhalten beide Displays"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Gerät ist zu warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen ist nicht verfügbar, weil dein Smartphone zu warm ist"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ist nicht verfügbar"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ist nicht verfügbar, weil der Energiesparmodus aktiviert ist. Dies lässt sich in den Einstellungen deaktivieren."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Zu den Einstellungen"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Deaktivieren"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> konfiguriert"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Tastaturlayout festgelegt auf <xliff:g id="LAYOUT_1">%s</xliff:g>. Zum Ändern tippen."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 28b269b..fd20378 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> χρησιμοποιεί και τις δύο οθόνες για να εμφανίζει περιεχόμενο"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Η θερμοκρασία της συσκευής είναι πολύ υψηλή"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Η λειτουργία διπλής οθόνης δεν είναι διαθέσιμη επειδή η θερμοκρασία του τηλεφώνου αυξάνεται υπερβολικά"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Το Dual Screen δεν είναι διαθέσιμο"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Το Dual Screen δεν είναι διαθέσιμο επειδή η Εξοικονόμηση μπαταρίας είναι ενεργοποιημένη. Μπορείτε να απενεργοποιήσετε αυτήν τη λειτουργία στις Ρυθμίσεις."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Μεταβείτε στις Ρυθμίσεις"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Απενεργοποίηση"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Η συσκευή <xliff:g id="DEVICE_NAME">%s</xliff:g> διαμορφώθηκε"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Η διάταξη πληκτρολογίου ορίστηκε σε <xliff:g id="LAYOUT_1">%s</xliff:g>. Πατήστε για αλλαγή."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 4996e4f..3cee375 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using both displays to show content"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Device is too warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen is unavailable because your phone is getting too warm"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is unavailable"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is unavailable because Battery Saver is on. You can turn this off in Settings."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Go to Settings"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Turn off"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configured"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Keyboard layout set to <xliff:g id="LAYOUT_1">%s</xliff:g>. Tap to change."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 597569c..311c8a3 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1702,7 +1702,7 @@
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"View and control screen"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"It can read all content on the screen and display content over other apps."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"View and perform actions"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"It can track your interactions with an app or a hardware sensor, and interact with apps on your behalf."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"It can track your interactions with an app or a hardware sensor and interact with apps on your behalf."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Allow"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Deny"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tap a feature to start using it:"</string>
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using both displays to show content"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Device is too warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen is unavailable because your phone is getting too warm"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is unavailable"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is unavailable because Battery Saver is on. You can turn this off in Settings."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Go to Settings"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Turn off"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configured"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Keyboard layout set to <xliff:g id="LAYOUT_1">%s</xliff:g>. Tap to change."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 76fdcef..9c97a49 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using both displays to show content"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Device is too warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen is unavailable because your phone is getting too warm"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is unavailable"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is unavailable because Battery Saver is on. You can turn this off in Settings."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Go to Settings"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Turn off"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configured"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Keyboard layout set to <xliff:g id="LAYOUT_1">%s</xliff:g>. Tap to change."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 45afefc..86be1a9 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using both displays to show content"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Device is too warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen is unavailable because your phone is getting too warm"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is unavailable"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is unavailable because Battery Saver is on. You can turn this off in Settings."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Go to Settings"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Turn off"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configured"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Keyboard layout set to <xliff:g id="LAYOUT_1">%s</xliff:g>. Tap to change."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 6c57327..44426d7 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> is using both displays to show content"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Device is too warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dual Screen is unavailable because your phone is getting too warm"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is unavailable"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is unavailable because Battery Saver is on. You can turn this off in Settings."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Go to Settings"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Turn off"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configured"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Keyboard layout set to <xliff:g id="LAYOUT_1">%s</xliff:g>. Tap to change."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index b221b9e..9d06e15 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi‑Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Llamada por Wi‑Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWiFi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Llamada Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Desactivado"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Llamar a través de la red Wi‑Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Llamar a través de la red móvil"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> está usando ambas pantallas para mostrar contenido"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"El dispositivo está demasiado caliente"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Cámara Dual no está disponible porque el teléfono se está calentando demasiado"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen no está disponible"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen no está disponible porque la función Ahorro de batería está activada. Puedes desactivarla en Ajustes."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ir a Ajustes"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desactivar"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Se ha configurado <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%s</xliff:g>. Toca para cambiarlo."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index f4f3c4d..78f5749 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"WiFi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WiFi-kõned"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WiFi-kõne"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Väljas"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Helista WiFi kaudu"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Helista mobiilsidevõrgu kaudu"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> kasutab sisu kuvamiseks mõlemat ekraani"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Seade on liiga kuum"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Kahe ekraani režiim pole saadaval, kuna teie telefon läheb liiga kuumaks"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Kahe ekraani režiim ei ole saadaval"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Kahe ekraani režiim ei ole saadaval, kuna akusäästja on sisse lülitatud. Saate selle seadetes välja lülitada."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ava seaded"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Lülita välja"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> on seadistatud"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Klaviatuuripaigutuseks on määratud <xliff:g id="LAYOUT_1">%s</xliff:g>. Puudutage muutmiseks."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3ca55e2..53644927 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wifia"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi bidezko deiak"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wifi bidezko deia"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Desaktibatuta"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Deitu wifi bidez"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Deitu sare mugikorraren bidez"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> bi pantailak erabiltzen ari da edukia erakusteko"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Gailua beroegi dago"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Bi pantailako modua ez dago erabilgarri telefonoa berotzen ari delako"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ez dago erabilgarri"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ez dago erabilgarri, bateria-aurreztailea aktibatuta dagoelako. Aukera hori desaktibatzeko, joan ezarpenetara."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Joan Ezarpenak atalera"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desaktibatu"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Konfiguratu da <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Ezarri da <xliff:g id="LAYOUT_1">%s</xliff:g> gisa teklatuaren diseinua. Diseinu hori aldatzeko, sakatu hau."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5473cec..88dd3a6 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"تماس ازطریق WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"تماس Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"خاموش"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"تماس ازطریق Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"تماس ازطریق شبکه تلفن همراه"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> از هر دو نمایشگر برای نمایش محتوا استفاده میکند"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"دستگاه بیشازحد گرم شده است"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"«صفحه دوتایی» دردسترس نیست زیرا تلفن بیشازحد گرم شده است"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen دردسترس نیست"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen دردسترس نیست چون «بهینهسازی باتری» روشن است. میتوانید این ویژگی را در «تنظیمات» خاموش کنید."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"رفتن به تنظیمات"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"خاموش کردن"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> پیکربندی شد"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"طرحبندی صفحهکلید روی <xliff:g id="LAYOUT_1">%s</xliff:g> تنظیم شد. برای تغییر دادن، ضربه بزنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9ec3fba..f007d74 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-puhelut"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi-puhelu"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Ei päällä"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Soita Wi-Fin kautta"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Soita mobiiliverkon kautta"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 04597fa..409f5a2 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Appels Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"Voix par Wi-Fi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Appel Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Désactivé"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Appels par Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Appels sur réseau cellulaire"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ff74083..7de81a5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Appels Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWiFi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Appel Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Désactivé"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Appel via le Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Appel via le réseau mobile"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> utilise les deux écrans pour afficher du contenu"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"L\'appareil est trop chaud"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Double écran n\'est pas disponible, car votre téléphone surchauffe"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Double écran n\'est pas disponible"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Double écran n\'est pas disponible, car Économiseur de batterie est activé. Vous pouvez désactiver cette option dans les paramètres."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Accédez aux paramètres"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Désactiver"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configuré"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Disposition du clavier définie sur <xliff:g id="LAYOUT_1">%s</xliff:g>. Appuyez pour la modifier."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 1f86aa5..d748991 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wifi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Chamadas por wifi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Chamada por wifi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Desactivado"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Chama por wifi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Chama pola rede de telefonía móbil"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 1122ce7..53d7fd8 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"વાઇ-ફાઇ"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"વાઇ-ફાઇ કૉલિંગ"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"વાઇ ફાઇ કૉલ"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"બંધ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"વાઇ-ફાઇ પરથી કૉલ કરો"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"મોબાઇલ નેટવર્ક પરથી કૉલ કરો"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"કન્ટેન્ટ બતાવવા માટે <xliff:g id="APP_NAME">%1$s</xliff:g> બન્ને ડિસ્પ્લેનો ઉપયોગ કરી રહી છે"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ડિવાઇસ ખૂબ જ ગરમ છે"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ડ્યૂઅલ સ્ક્રીન અનુપલબ્ધ છે કારણ કે તમારો ફોન ખૂબ જ ગરમ થઈ રહ્યો છે"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ડ્યૂઅલ સ્ક્રીન અનુપલબ્ધ છે"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"બૅટરી સેવર ચાલુ હોવાને કારણે ડ્યૂઅલ સ્ક્રીન અનુપલબ્ધ છે. તમે સેટિંગમાં જઈને આને બંધ કરી શકો છો."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"સેટિંગ પર જાઓ"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"બંધ કરો"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g>ની ગોઠવણી કરવામાં આવી છે"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"કીબોર્ડનું લેઆઉટ <xliff:g id="LAYOUT_1">%s</xliff:g> પર સેટ કરવામાં આવ્યું છે. બદલવા માટે ટૅપ કરો."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 2fe9a29..84f0490 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"वाई-फ़ाई"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"वाई-फ़ाई कॉलिंग"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"वाई-फ़ाई कॉल"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"बंद"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"वाई-फ़ाई के ज़रिए कॉल करें"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"मोबाइल नेटवर्क के ज़रिए कॉल"</string>
@@ -1701,7 +1700,7 @@
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> को अपना डिवाइस पूरी तरह कंट्रोल करने की मंज़ूरी दें?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"पूरी तरह कंट्रोल करने की अनुमति उन ऐप्लिकेशन के लिए ठीक है जो सुलभता से जुड़ी ज़रूरतों के लिए बने हैं, लेकिन ज़्यादातर ऐप्लिकेशन के लिए यह ठीक नहीं है."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रीन को देखें और कंट्रोल करें"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यह स्क्रीन पर दिखने वाली हर तरह के कॉन्टेंट को पढ़ सकता है और उसे दूसरे ऐप्लिकेशन पर दिखा सकता है."</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यह स्क्रीन पर दिखने वाले कॉन्टेंट को पढ़ सकता है और उसे दूसरे ऐप्लिकेशन के ऊपर दिखा सकता है."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"देखें और कार्रवाई करें"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"यह आपके और किसी ऐप्लिकेशन या हार्डवेयर सेंसर के बीच होने वाले इंटरैक्शन को ट्रैक कर सकता है और आपकी तरफ़ से ऐप्लिकेशन के साथ इंटरैक्ट कर सकता है."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमति दें"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>, कॉन्टेंट दिखाने के लिए दोनों डिसप्ले का इस्तेमाल कर रहा है"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"आपका फ़ोन बहुत गर्म हो गया है"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ड्यूअल स्क्रीन की सुविधा अभी उपलब्ध नहीं है, क्योंकि आपका फ़ोन बहुत गर्म हो रहा है"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen का इस्तेमाल नहीं किया जा सकता"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"बैटरी सेवर की सुविधा चालू होने पर, Dual Screen का इस्तेमाल नहीं किया जा सकता. इस सुविधा को सेटिंग में जाकर बंद करें."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"सेटिंग पर जाएं"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"बंद करें"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> कॉन्फ़िगर किया गया"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"कीबोर्ड का लेआउट <xliff:g id="LAYOUT_1">%s</xliff:g> पर सेट कर दिया गया है. बदलने के लिए टैप करें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 5bdbd1e..eff5524 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2325,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> upotrebljava oba zaslona za prikazivanje sadržaja"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Uređaj se pregrijao"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dvostruki zaslon nije podržan jer se vaš telefon pregrijao"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Značajka Dual Screen nije dostupna"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Značajka Dual Screen nije dostupna jer je uključena štednja baterije. To možete isključiti u postavkama."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Otvorite Postavke"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Isključi"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Konfiguriran je uređaj <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Raspored tipkovnice postavljen je na <xliff:g id="LAYOUT_1">%s</xliff:g>. Dodirnite da biste ga promijenili."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 6f996e5..e61aba4 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi-hívás"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi-hívás"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Ki"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Hívás Wi-Fi-hálózaton"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Hívás mobilhálózaton"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> mindkét kijelzőt használja a tartalmak megjelenítésére"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Az eszköz túl meleg"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"A Két képernyő funkció nem áll rendelkezésre, mert a telefon melegedni kezdett"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"A Két képernyő funkció nem használható"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"A Két képernyő funkció nem használható, mert az Akkumulátorkímélő mód be van kapcsolva. Ezt a funkciót a beállítások között lehet kikapcsolni."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Lépjen a Beállítások menübe"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Kikapcsolás"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> beállítva"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"A billentyűzetkiosztás a következőre van beállítva: <xliff:g id="LAYOUT_1">%s</xliff:g>. A módosításhoz koppintson."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index f1004de1..b1e226e 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Զանգեր Wi-Fi-ի միջոցով"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Զանգ Wi-Fi-ի միջոցով"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Անջատված է"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Զանգ Wi-Fi-ի միջոցով"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Զանգ բջջային ցանցի միջոցով"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 150629f..ca97e22 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Panggilan WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Panggilan Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Nonaktif"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Panggilan telepon melalui Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Panggilan telepon melalui jaringan seluler"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> menggunakan kedua layar untuk menampilkan konten"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Suhu perangkat terlalu panas"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Layar ganda tidak tersedia karena suhu ponsel terlalu panas"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen tidak tersedia"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen tidak tersedia karena Penghemat Baterai aktif. Anda dapat menonaktifkannya di Setelan."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Buka Setelan"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Nonaktifkan"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> telah dikonfigurasi"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Tata letak keyboard disetel ke <xliff:g id="LAYOUT_1">%s</xliff:g>. Ketuk untuk mengubah."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 10b7549..77ade61 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WiFi símtöl"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WiFi-símtal"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Slökkt"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Hringja í gegnum Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Hringja í gegnum farsímakerfi"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> er að nota báða skjái til að sýna efni"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Tækið er of heitt"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Tveir skjáir eru ekki í boði vegna þess að síminn er of heitur"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen er ekki í boði"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen er ekki í boði vegna þess að kveikt er á rafhlöðusparnaði. Þú getur slökkt á þessu í stillingunum."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Opna stillingar"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Slökkva"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> er stillt"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Lyklaskipan er stillt á <xliff:g id="LAYOUT_1">%s</xliff:g>. Ýttu til að breyta."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 8cae14d..8d57810 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1701,7 +1701,7 @@
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"Vuoi consentire a <xliff:g id="SERVICE">%1$s</xliff:g> di avere il controllo totale del tuo dispositivo?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"Il controllo totale è appropriato per le app che rispondono alle tue esigenze di accessibilità, ma non per gran parte delle app."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Visualizzare e controllare lo schermo"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Può leggere i contenuti presenti sullo schermo e mostrare i contenuti su altre app."</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Può leggere tutti i contenuti presenti sullo schermo e mostrare i contenuti sopra altre app."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Visualizzare ed eseguire azioni"</string>
<string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Può tenere traccia delle tue interazioni con un\'app o un sensore hardware e interagire con app per tuo conto."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Consenti"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index aa81d6a..9e283fa 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"שיחות Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"שיחת WiFi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"כבוי"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"שיחה בחיבור Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"שיחה ברשת סלולרית"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> משתמשת בשני המסכים כדי להציג תוכן"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"המכשיר חם מדי"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"מצב שני מסכים לא זמין כי הטלפון נהיה חם מדי"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"התכונה Dual Screen לא זמינה"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"התכונה Dual Screen לא זמינה כי מצב החיסכון בסוללה מופעל. אפשר להשבית את האפשרות הזו בהגדרות."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"מעבר להגדרות"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"השבתה"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"המקלדת <xliff:g id="DEVICE_NAME">%s</xliff:g> הוגדרה"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"פריסת המקלדת מוגדרת ל<xliff:g id="LAYOUT_1">%s</xliff:g>. אפשר להקיש כדי לשנות את ההגדרה הזו."</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7fdb8d9..af735ea 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> იყენებს ორივე ეკრანს შინაარსის საჩვენებლად"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"მოწყობილობა ძალიან თბილია"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ორმაგი ეკრანი მიუწვდომელია, რადგან თქვენი ტელეფონი ძალიან თბება"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen მიუწვდომელია"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen მიუწვდომელია, რადგან ჩართულია ბატარეის დამზოგი. ამის გამორთვა პარამეტრებიდან შეგიძლიათ."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"პარამეტრებზე გადასვლა"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"გამორთვა"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> კონფიგურირებულია"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"დაყენდა კლავიატურის განლაგება: <xliff:g id="LAYOUT_1">%s</xliff:g>. შეეხეთ შესაცვლელად."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 32e3f59..5fbe915 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WiFi қоңыраулары"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi қоңырауы"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Өшірулі"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi арқылы қоңырау шалу"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Мобильдік желі арқылы қоңырау шалу"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы контентті көрсету үшін екі дисплейді де пайдаланады."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Құрылғы қатты қызып кетті."</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Қос экран функциясы істемейді, себебі телефон қатты қызып кетеді."</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen қолжетімсіз"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Батареяны үнемдеу режимі қосулы болғандықтан, Dual Screen қолжетімсіз. Мұны параметрлерден өшіруге болады."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Параметрлерге өту"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Өшіру"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> конфигурацияланды"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Пернетақта форматы <xliff:g id="LAYOUT_1">%s</xliff:g> деп орнатылды. Өзгерту үшін түртіңіз."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 1f72495..f69ff8a 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"ការហៅតាម Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"ការហៅទូរសព្ទតាម Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"បិទ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"ហៅទូរសព្ទតាមរយៈ Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ហៅទូរសព្ទតាមរយៈបណ្តាញទូរសព្ទចល័ត"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងប្រើផ្ទាំងអេក្រង់ទាំងពីរដើម្បីបង្ហាញខ្លឹមសារ"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ឧបករណ៍ក្តៅពេក"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"អេក្រង់ពីរមិនអាចប្រើបានទេ ដោយសារទូរសព្ទរបស់អ្នកឡើងក្តៅពេក"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"មិនអាចប្រើ Dual Screen បានទេ"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"មិនអាចប្រើ Dual Screen បានទេ ដោយសារមុខងារសន្សំថ្មត្រូវបានបើក។ អ្នកអាចបិទវាបាននៅក្នុងការកំណត់។"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ចូលទៅកាន់ \"ការកំណត់\""</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"បិទ"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"បានកំណត់រចនាសម្ព័ន្ធ <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"បានកំណត់ប្លង់ក្ដារចុចទៅ <xliff:g id="LAYOUT_1">%s</xliff:g>។ សូមចុចដើម្បីប្ដូរ។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 062cc67..b503d6b 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"ವೈ-ಫೈ"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"ವೈಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"ವೈ-ಫೈ ಕರೆ"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ಆಫ್"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"ವೈ-ಫೈ ಬಳಸಿ ಕರೆ ಮಾಡಿ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಬಳಸಿ ಕರೆ ಮಾಡಿ"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"ವಿಷಯವನ್ನು ತೋರಿಸಲು <xliff:g id="APP_NAME">%1$s</xliff:g> ಎರಡೂ ಡಿಸ್ಪ್ಲೇಗಳನ್ನು ಬಳಸುತ್ತದೆ"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ಸಾಧನವು ತುಂಬಾ ಬಿಸಿಯಾಗಿದೆ"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ನಿಮ್ಮ ಫೋನ್ ತುಂಬಾ ಬಿಸಿಯಾಗುವುದರಿಂದ ಡ್ಯೂಯಲ್ ಸ್ಕ್ರೀನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಆಗಿರುವ ಕಾರಣ Dual Screen ಲಭ್ಯವಿಲ್ಲ. ನೀವು ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಇದನ್ನು ಆಫ್ ಮಾಡಬಹುದು."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ಆಫ್ ಮಾಡಿ"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಅನ್ನು <xliff:g id="LAYOUT_1">%s</xliff:g> ಗೆ ಸೆಟ್ ಮಾಡಲಾಗಿದೆ. ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5a982e5..78dd9ec 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi 통화"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi 통화"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"꺼짐"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi를 통해 통화"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"모바일 네트워크를 통해 통화"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 두 화면을 모두 사용하여 콘텐츠를 표시합니다."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"기기 온도가 너무 높음"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"휴대전화 온도가 너무 높아지고 있으므로 듀얼 스크린을 사용할 수 없습니다."</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen을 사용할 수 없음"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"절전 모드가 사용 설정되어 있어 Dual Screen을 사용할 수 없습니다. 설정에서 이 기능을 사용 중지할 수 있습니다."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"설정으로 이동"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"사용 중지"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g>에 설정 완료됨"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"키보드 레이아웃이 <xliff:g id="LAYOUT_1">%s</xliff:g>(으)로 설정됩니다. 변경하려면 탭하세요."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 48c2c7b..5e3e3d9 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi‑Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi аркылуу чалынууда"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WiFi аркылуу чалуу"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Өчүк"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi аркылуу чалуу"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Мобилдик тармак аркылуу чалуу"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> контентти эки түзмөктө тең көрсөтүүдө"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Түзмөк ысып кетти"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Телефонуңуз ысып кеткендиктен, Кош экран функциясы жеткиликсиз"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen жеткиликсиз"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen жеткиликсиз, анткени Батареяны үнөмдөгүч режими күйүк. Муну параметрлерден өчүрсөңүз болот."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Параметрлерге өтүү"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Өчүрүү"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> конфигурацияланды"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Баскычтоп калыбы төмөнкүгө коюлду: <xliff:g id="LAYOUT_1">%s</xliff:g>. Өзгөртүү үчүн басыңыз."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 5b67814..700940d 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"ການໂທ Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"ການໂທ Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ປິດ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"ໂທຜ່ານ Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ໂທຜ່ານເຄືອຂ່າຍມືຖື"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງໃຊ້ຈໍສະແດງຜົນທັງສອງເພື່ອສະແດງເນື້ອຫາ"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ອຸປະກອນຮ້ອນເກີນໄປ"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ໜ້າຈໍຄູ່ບໍ່ພ້ອມໃຫ້ນຳໃຊ້ເນື່ອງຈາກໂທລະສັບຂອງທ່ານຮ້ອນເກີນໄປ"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ໃຊ້ບໍ່ໄດ້"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ໃຊ້ບໍ່ໄດ້ເນື່ອງຈາກເປີດຕົວປະຢັດແບັດເຕີຣີຢູ່. ທ່ານສາມາດປິດສິ່ງນີ້ໄດ້ໃນການຕັ້ງຄ່າ."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ເຂົ້າໄປການຕັ້ງຄ່າ"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ປິດໄວ້"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"ຕັ້ງຄ່າ <xliff:g id="DEVICE_NAME">%s</xliff:g> ແລ້ວ"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"ຕັ້ງຄ່າໂຄງຮ່າງແປ້ນພິມເປັນ <xliff:g id="LAYOUT_1">%s</xliff:g>. ແຕະເພື່ອປ່ຽນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6793454..86b8903 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -142,8 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"„Wi-Fi“ skambinimas"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"„Wi-Fi“ skambutis"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Išjungta"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Skambinimas naudojant „Wi-Fi“"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Skambinimas naudojant mobiliojo ryšio tinklą"</string>
@@ -2327,12 +2326,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ naudoja abu ekranus turiniui rodyti"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Įrenginys per daug kaista"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dvigubas ekranas nepasiekiamas, nes telefonas per daug kaista"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Funkcija „Dual Screen“ nepasiekiama"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Funkcija „Dual Screen“ nepasiekiama, nes įjungta Akumuliatoriaus tausojimo priemonė. Šią parinktį bet kada galite išjungti skiltyje „Nustatymai“."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Eiti į skiltį „Nustatymai“"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Išjungti"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Įrenginys „<xliff:g id="DEVICE_NAME">%s</xliff:g>“ sukonfigūruotas"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Klaviatūros išdėstymas nustatytas į <xliff:g id="LAYOUT_1">%s</xliff:g>. Palieskite, kad pakeistumėte."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 56f2241..123e43a 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi zvani"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi zvans"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Izslēgts"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Zvani Wi-Fi tīklā"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Zvani mobilajā tīklā"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> satura rādīšanai izmanto abus displejus."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Ierīce ir pārāk sakarsusi"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Divu ekrānu režīms nav pieejams, jo tālrunis sāk pārāk sakarst."</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Divu ekrānu režīms nav pieejams"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Divu ekrānu režīms nav pieejams, jo ir ieslēgts akumulatora enerģijas taupīšanas režīms. To var izslēgt iestatījumos."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Atvērt iestatījumus"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Izslēgt"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ir konfigurēta"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Ir iestatīts šāds tastatūras izkārtojums: <xliff:g id="LAYOUT_1">%s</xliff:g>. Lai to mainītu, pieskarieties."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 1002bdf..746f06f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Повикување преку Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"Глас преку Wi-Fi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Повик преку WiFi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Исклучено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Повикувај преку Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Повикувај преку мобилна мрежа"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> ги користи двата екрани за да прикажува содржини"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Уредот е претопол"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Двојниот екран е недостапен бидејќи вашиот телефон станува претопол"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"„Двојниот екран“ е недостапен"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Двојниот екран е недостапен бидејќи е вклучен „Штедач на батерија“. Ова може да се исклучи во „Поставки“."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Одете во „Поставките“"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Исклучи"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> е конфигуриран"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Распоредот на тастатурата е поставен на <xliff:g id="LAYOUT_1">%s</xliff:g>. Допрете за да промените."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 7e08328..69c96f3 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"വൈഫൈ"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"വൈഫൈ കോളിംഗ്"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"Voവൈഫൈ"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"വൈഫൈ കോൾ"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ഓഫ്"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"വൈഫൈ മുഖേനയുള്ള കോൾ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"മൊബൈൽ നെറ്റ്വർക്ക് മുഖേനയുള്ള കോൾ"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"ഉള്ളടക്കം കാണിക്കാൻ <xliff:g id="APP_NAME">%1$s</xliff:g> രണ്ട് ഡിസ്പ്ലേകളും ഉപയോഗിക്കുന്നു"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ഉപകരണത്തിന് ചൂട് കൂടുതലാണ്"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"നിങ്ങളുടെ ഫോൺ വളരെയധികം ചൂടാകുന്നതിനാൽ ഡ്യുവൽ സ്ക്രീൻ ലഭ്യമല്ല"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ഡ്യുവൽ സ്ക്രീൻ ലഭ്യമല്ല"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ബാറ്ററി ലാഭിക്കൽ ഓണായതിനാൽ ഡ്യുവൽ സ്ക്രീൻ ലഭ്യമല്ല. നിങ്ങൾക്ക് ഇത് ക്രമീകരണത്തിൽ ഓഫാക്കാം."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ക്രമീകരണത്തിലേക്ക് പോകുക"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ഓഫാക്കുക"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> കോൺഫിഗർ ചെയ്തു"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"കീബോർഡ് ലേഔട്ട് ആയി <xliff:g id="LAYOUT_1">%s</xliff:g> സജ്ജീകരിച്ചു. മാറ്റാൻ ടാപ്പ് ചെയ്യുക."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index b83f9fd..18aa7bc 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi дуудлага"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi дуудлага"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Идэвхгүй"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi-р залгах"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Мобайл сүлжээгээр дуудлага хийх"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> контент харуулахын тулд хоёр дэлгэцийг хоёуланг нь ашиглаж байна"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Төхөөрөмж хэт халуун байна"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Таны утас хэт халж байгаа тул Хоёр дэлгэц боломжгүй байна"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen боломжгүй байна"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Батарей хэмнэгч асаалттай байгаа тул Dual Screen боломжгүй байна. Та үүнийг Тохиргоонд унтрааж болно."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Тохиргоо руу очих"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Унтраах"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g>-г тохируулсан"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Гарын бүдүүвчийг <xliff:g id="LAYOUT_1">%s</xliff:g> болгож тохируулсан. Өөрчлөхийн тулд товшино уу."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4da7c71..e1b45f92 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -627,11 +627,11 @@
<string name="biometric_error_generic" msgid="6784371929985434439">"एरर ऑथेंटिकेट करत आहे"</string>
<string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रीन लॉक वापरा"</string>
<string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"पुढे सुरू ठेवण्यासाठी तुमचे स्क्रीन लॉक एंटर करा"</string>
- <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरवर जोरात दाबा"</string>
+ <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरवर जोरात प्रेस करा"</string>
<string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"फिंगरप्रिंट ओळखता आली नाही. पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिंट सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string>
<string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string>
- <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात दाबा"</string>
+ <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात प्रेस करा"</string>
<string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"बोट खूप सावकाश हलविले. कृपया पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पहा"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"खूप प्रखर"</string>
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"आशय दाखवण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> दोन्ही डिस्प्ले वापरत आहे"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"डिव्हाइस खूप गरम आहे"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"तुमचा फोन खूप गरम होत असल्यामुळे ड्युअल स्क्रीन उपलब्ध नाही"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ड्युअल स्क्रीन उपलब्ध नाही"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"बॅटरी सेव्हर सुरू असल्यामुळे ड्युअल स्क्रीन उपलब्ध नाही. तुम्ही हे सेटिंग्ज मध्ये बंद करू शकता."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"सेटिंग्ज वर जा"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"बंद करा"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> कॉंफिगर केले आहे"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"कीबोर्ड लेआउट <xliff:g id="LAYOUT_1">%s</xliff:g> वर सेट केला. बदलण्यासाठी टॅप करा."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index d780cba..faf3b0c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Panggilan Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Panggilan Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Mati"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Panggil melalui Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Panggil melalui rangkaian mudah alih"</string>
@@ -2030,7 +2029,7 @@
<string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Kemas kini <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> dalam "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
<string name="autofill_update_title_with_3types" msgid="1312232153076212291">"Kemas kini item ini dalam "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dan <xliff:g id="TYPE_2">%3$s</xliff:g> ?"</string>
<string name="autofill_save_yes" msgid="8035743017382012850">"Simpan"</string>
- <string name="autofill_save_no" msgid="9212826374207023544">"Tidak, terima kasih"</string>
+ <string name="autofill_save_no" msgid="9212826374207023544">"Tidak perlu"</string>
<string name="autofill_save_notnow" msgid="2853932672029024195">"Bukan sekarang"</string>
<string name="autofill_save_never" msgid="6821841919831402526">"Jangan"</string>
<string name="autofill_update_yes" msgid="4608662968996874445">"Kemas kini"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> menggunakan kedua-dua paparan untuk menunjukkan kandungan"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Peranti terlalu panas"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dwiskrin tidak tersedia kerana telefon anda terlalu panas"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen tidak tersedia"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen tidak tersedia kerana Penjimat Bateri dihidupkan. Anda boleh mematikan ciri ini dalam Tetapan."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Akses Tetapan"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Matikan"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> dikonfigurasikan"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Reka letak papan kekunci ditetapkan kepada <xliff:g id="LAYOUT_1">%s</xliff:g>. Ketik untuk menukar reka letak."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 9a72679..da4ff15 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WiFi ခေါ်ဆိုမှု"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WiFi ခေါ်ဆိုမှု"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ပိတ်"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi သုံး၍ ခေါ်ဆိုသည်"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"မိုဘိုင်းကွန်ရက်သုံး၍ ခေါ်ဆိုသည်"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် အကြောင်းအရာကို ဖန်သားပြင်နှစ်ခုစလုံးတွင် ပြနေသည်"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"စက်ပစ္စည်း အလွန်ပူနေသည်"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"သင့်ဖုန်း အလွန်ပူနေသဖြင့် ‘စခရင်နှစ်ခု’ သုံး၍မရပါ"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen သုံး၍မရပါ"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"‘ဘက်ထရီ အားထိန်း’ ဖွင့်ထားသဖြင့် Dual Screen သုံး၍မရပါ။ ၎င်းကို ဆက်တင်များတွင် ပိတ်နိုင်သည်။"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ဆက်တင်များသို့ သွားရန်"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ပိတ်ရန်"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> စီစဉ်သတ်မှတ်ထားသည်"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"ကီးဘုတ်အပြင်အဆင်ကို <xliff:g id="LAYOUT_1">%s</xliff:g> ဟု သတ်မှတ်ထားသည်။ ပြောင်းရန်တို့ပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 979d464..2f59013 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wifi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wifi-anrop"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wifi-anrop"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Av"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Ring via Wifi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Ring over mobilnettverk"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 886b27c..52775d0 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WiFi कलिङ"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi कल"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"अफ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi मार्फत कल गर्नुहोस्"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"मोबाइल नेटवर्कमार्फत कल गर्नुहोस्"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले सामग्री देखाउन दुई वटै डिस्प्ले प्रयोग गरिरहेको छ"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"डिभाइस ज्यादै तातेको छ"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"तपाईंको फोन ज्यादै तातिरहेको हुनाले डुअल स्क्रिन उपलब्ध छैन"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen उपलब्ध छैन"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ब्याट्री सेभर अन भएकाले Dual Screen उपलब्ध छैन। तपाईं सेटिङमा गई यो सुविधा अफ गर्न सक्नुहुन्छ।"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"सेटिङमा जानुहोस्"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"अफ गर्नुहोस्"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> कन्फिगर गरिएको छ"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"किबोर्ड लेआउट सेट गरी <xliff:g id="LAYOUT_1">%s</xliff:g> बनाइएको छ। परिवर्तन गर्न ट्याप गर्नुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 97d277d..64ae814 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wifi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Bellen via wifi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wifi-gesprek"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Uit"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Bellen via wifi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Bellen via mobiel netwerk"</string>
@@ -1701,9 +1700,9 @@
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"Toestaan dat <xliff:g id="SERVICE">%1$s</xliff:g> volledige controle over je apparaat heeft?"</string>
<string name="accessibility_service_warning_description" msgid="291674995220940133">"Volledige controle is gepast voor apps die je helpen met toegankelijkheid, maar niet voor de meeste apps."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Scherm bekijken en bedienen"</string>
- <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"De functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string>
+ <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Deze functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Acties bekijken en uitvoeren"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"De functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Deze functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Toestaan"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Weigeren"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tik op een functie om deze te gebruiken:"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> gebruikt beide schermen om content te tonen"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Het apparaat is te warm"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dubbel scherm is niet beschikbaar, omdat je telefoon te warm wordt"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen is niet beschikbaar"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen is niet beschikbaar omdat Batterijbesparing aanstaat. Je kunt dit uitzetten via Instellingen."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Naar Instellingen"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Uitzetten"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> is ingesteld"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Toetsenbordindeling ingesteld op <xliff:g id="LAYOUT_1">%s</xliff:g>. Tik om te wijzigen."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index bc28604..09ae262 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"ୱାଇ-ଫାଇ"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"ୱାଇଫାଇ କଲିଂ"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"ୱାଇଫାଇ କଲ"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ବନ୍ଦ ଅଛି"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ କଲ୍ କରନ୍ତୁ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ମୋବାଇଲ ନେଟ୍ୱର୍କ ମାଧ୍ୟମରେ କଲ୍ କରନ୍ତୁ"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"ବିଷୟବସ୍ତୁ ଦେଖାଇବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଉଭୟ ଡିସପ୍ଲେକୁ ବ୍ୟବହାର କରୁଛି"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"ଡିଭାଇସ ବହୁତ ଗରମ ଅଛି"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"ଆପଣଙ୍କ ଫୋନ ବହୁତ ଗରମ ହେଉଥିବା ଯୋଗୁଁ ଡୁଆଲ ସ୍କ୍ରିନ ଉପଲବ୍ଧ ନାହିଁ"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"ଡୁଆଲ ସ୍କ୍ରିନ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"ବେଟେରୀ ସେଭର ଚାଲୁ ଥିବା ଯୋଗୁଁ ଡୁଆଲ ସ୍କ୍ରିନ ଉପଲବ୍ଧ ନାହିଁ। ଆପଣ ସେଟିଂସରେ ଏହାକୁ ବନ୍ଦ କରିପାରିବେ।"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ସେଟିଂସକୁ ଯାଆନ୍ତୁ"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g>କୁ କନଫିଗର କରାଯାଇଛି"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"କୀବୋର୍ଡ ଲେଆଉଟକୁ <xliff:g id="LAYOUT_1">%s</xliff:g>ରେ ସେଟ କରାଯାଇଛି। ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index e188a0d..6ec3eda 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"ਵਾਈ-ਫਾਈ"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"ਵਾਈ-ਫਾਈ ਕਾਲ"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ਬੰਦ"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"ਵਾਈ-ਫਾਈ \'ਤੇ ਕਾਲ ਕਰੋ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਤੋਂ ਕਾਲ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 031d576..274af13 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2326,12 +2326,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> korzysta z obu wyświetlaczy, aby pokazać treści"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Urządzenie jest za ciepłe"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Podwójny ekran jest niedostępny, ponieważ telefon za bardzo się nagrzewa"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Funkcja Dual Screen jest niedostępna"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Funkcja Dual Screen jest niedostępna, ponieważ włączono Oszczędzanie baterii. Możesz to wyłączyć w Ustawieniach."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Otwórz ustawienia"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Wyłącz"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Skonfigurowano urządzenie <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Ustawiono układ klawiatury <xliff:g id="LAYOUT_1">%s</xliff:g>. Kliknij, aby to zmienić."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index a315bb1..6d44196 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2325,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está usando as duas telas para mostrar conteúdo"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"O dispositivo está muito quente"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"A tela dupla está indisponível porque o smartphone está ficando muito quente"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"O recurso Dual Screen está indisponível"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"O recurso Dual Screen está indisponível porque a Economia de bateria está ativada. É possível desativar essa opção nas configurações."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ir para Configurações"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desativar"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Dispositivo <xliff:g id="DEVICE_NAME">%s</xliff:g> configurado"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Layout do teclado definido como <xliff:g id="LAYOUT_1">%s</xliff:g>. Toque para mudar."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5a68166..ff4fe09 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -2325,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a usar ambos os ecrãs para mostrar conteúdo"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"O dispositivo está a ficar demasiado quente"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"A funcionalidade Dois ecrãs está indisponível porque o seu telemóvel está a ficar demasiado quente"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"A funcionalidade Dual Screen está indisponível"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"A funcionalidade Dual Screen está indisponível porque a Poupança de bateria está ativada. Pode desativar esta opção nas Definições."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Aceder às Definições"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desativar"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Dispositivo <xliff:g id="DEVICE_NAME">%s</xliff:g> configurado"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Esquema do teclado definido como <xliff:g id="LAYOUT_1">%s</xliff:g>. Toque para o alterar."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a315bb1..6d44196 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2325,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está usando as duas telas para mostrar conteúdo"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"O dispositivo está muito quente"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"A tela dupla está indisponível porque o smartphone está ficando muito quente"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"O recurso Dual Screen está indisponível"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"O recurso Dual Screen está indisponível porque a Economia de bateria está ativada. É possível desativar essa opção nas configurações."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Ir para Configurações"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desativar"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Dispositivo <xliff:g id="DEVICE_NAME">%s</xliff:g> configurado"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Layout do teclado definido como <xliff:g id="LAYOUT_1">%s</xliff:g>. Toque para mudar."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 14570f7..b425883 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Apelare prin Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Apelare prin Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Dezactivată"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Apelează prin Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Sună prin rețeaua mobilă"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> folosește ambele ecrane pentru a afișa conținut"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Dispozitivul este prea cald"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Funcția Dual Screen este indisponibilă, deoarece telefonul s-a încălzit prea tare"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Funcția Dual Screen este indisponibilă"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Funcția Dual Screen este indisponibilă, deoarece s-a activat Economisirea bateriei. Poți dezactiva această opțiune din Setări."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Accesează Setările"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Dezactivează"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"S-a configurat <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Aspectul tastaturii este setat la <xliff:g id="LAYOUT_1">%s</xliff:g>. Atinge pentru a-l schimba."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 3dffa92..eccd18d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -142,8 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Звонки по Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Звонок по Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Отключено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Звонить по Wi‑Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Звонить по мобильной сети"</string>
@@ -2327,12 +2326,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> показывает контент на обоих экранах."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Устройство перегрелось"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Двойной экран недоступен из-за перегрева телефона."</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Функция Dual Screen недоступна"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Функция Dual Screen недоступна, так как включен режим энергосбережения. Вы можете отключить его в настройках."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Открыть настройки"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Отключить"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Устройство \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\" настроено"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Для клавиатуры настроена раскладка <xliff:g id="LAYOUT_1">%s</xliff:g>. Нажмите, чтобы изменить."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 93302ff..01b04ec 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi ඇමතීම"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WiFi ඇමතුම"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ක්රියාවිරහිතයි"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi ඔස්සේ ඇමතුම"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"ජංගම ජාලය ඔස්සේ ඇමතුම"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 3ab9547..2894896 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -142,8 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Volanie cez Wi‑Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Hovor cez Wi‑Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Vypnuté"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Volanie cez Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Volanie cez mobilnú sieť"</string>
@@ -2327,12 +2326,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> zobrazuje obsah na oboch obrazovkách"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Zariadenie je príliš horúce"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dvojitá obrazovka nie je k dispozícii, pretože telefón sa prehrieva"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen nie je k dispozícii"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen nie je k dispozícii, pretože je zapnutý šetrič batérie. Môžete to vypnúť v Nastaveniach."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Prejsť do Nastavení"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Vypnúť"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Klávesnica <xliff:g id="DEVICE_NAME">%s</xliff:g> je nakonfigurovaná"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Rozloženie klávesnice je nastavené na jazyk <xliff:g id="LAYOUT_1">%s</xliff:g>. Môžete to zmeniť klepnutím."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index cdac333..6d1d8b0 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -142,8 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Klicanje prek Wi-Fi-ja"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"Govor prek Wi-Fi-ja"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Klic prek povezave Wifi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Izklopljeno"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Klic prek omrežja Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Klic prek mobilnega omrežja"</string>
@@ -2327,12 +2326,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> uporablja oba zaslona za prikaz vsebine."</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Naprava se pregreva"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Dvojni zaslon ni na voljo, ker se telefon pregreva."</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ni na voljo"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ni na voljo, ker je vklopljeno varčevanje z energijo baterije. To lahko izklopite v nastavitvah."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Odpri nastavitve"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Izklopi"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Naprava <xliff:g id="DEVICE_NAME">%s</xliff:g> je konfigurirana"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Razporeditev tipkovnice je nastavljena na »<xliff:g id="LAYOUT_1">%s</xliff:g>«. Za spremembo se dotaknite."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 436a00d..fc94221 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Telefonatë me WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Telefonatë me WiFi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Çaktivizuar"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Telefono nëpërmjet Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Telefono nëpërmjet rrjetit celular"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> po i përdor të dyja ekranet për të shfaqur përmbajtje"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Pajisja është shumë e nxehtë"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"\"Ekrani i dyfishtë\" nuk ofrohet sepse telefoni yt po nxehet shumë"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"\"Ekrani i dyfishtë\" nuk ofrohet"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"\"Ekrani i dyfishtë\" nuk ofrohet sepse \"Kursyesi i baterisë\" është aktiv. Mund ta çaktivizosh këtë te \"Cilësimet\"."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Shko te \"Cilësimet\""</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Çaktivizoje"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> u konfigurua"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Struktura e tastierës u caktua në: <xliff:g id="LAYOUT_1">%s</xliff:g>. Trokit për ta ndryshuar."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6187a69..deb4476 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -141,8 +141,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"WiFi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Позивање преко WiFi-а"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Позив преко WiFi-ја"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Искључено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Позивање преко WiFi-а"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Позив преко мобилне мреже"</string>
@@ -2326,12 +2325,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> користи оба екрана за приказивање садржаја"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Уређај је превише загрејан"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Двојни екран је недоступан јер је телефон превише загрејан"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen није доступан"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen није доступан зато што је Уштеда батерије укључена. То можете да искључите у подешавањима."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Иди у Подешавања"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Искључи"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Уређај <xliff:g id="DEVICE_NAME">%s</xliff:g> је конфигурисан"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Распоред тастатуре је подешен на <xliff:g id="LAYOUT_1">%s</xliff:g>. Додирните да бисте то променили."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 5278939..823c836 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wifi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"wifi-samtal"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wifi-samtal"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Av"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Ring via wifi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Ring via mobilnätverk"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1398271..e8861fd 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Kupiga simu kupitia WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Simu ya WiFi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Imezimwa"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Piga simu ukitumia WI-FI"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Piga ukitumia mtandao wa simu"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> inatumia skrini zote kuonyesha maudhui"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Kifaa kina joto sana"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Kipengele cha Hali ya Skrini Mbili hakipatikani kwa sababu simu yako inapata joto sana"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Kipengele cha Hali ya Skrini Mbili hakipatikani"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Kipengele cha Hali ya Skrini Mbili hakipatikani kwa sababu kipengele cha Kiokoa Betri kimewashwa. Unaweza kuzima kipengele hiki katika Mipangilio."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Nenda kwenye Mipangilio"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Zima"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> imewekewa mipangilio"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Muundo wa kibodi umewekwa kuwa <xliff:g id="LAYOUT_1">%s</xliff:g>. Gusa ili ubadilishe."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index a7eb123..6c3591e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"வைஃபை"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"வைஃபை அழைப்பு"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"வைஃபை அழைப்பு"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ஆஃப்"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"வைஃபை மூலம் அழை"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"மொபைல் நெட்வொர்க் மூலமாக அழை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 530c2e6..dce0377 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi కాలింగ్"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi కాల్"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ఆఫ్లో ఉంది"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Wi-Fi ద్వారా కాల్"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"మొబైల్ నెట్వర్క్ ద్వారా కాల్"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"కంటెంట్ను చూపడం కోసం <xliff:g id="APP_NAME">%1$s</xliff:g> రెండు డిస్ప్లేలనూ ఉపయోగిస్తుంది"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"పరికరం చాలా వేడిగా ఉంది"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"మీ ఫోన్ చాలా వేడిగా అవుతున్నందున, డ్యూయల్ స్క్రీన్ అందుబాటులో లేదు"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"డ్యూయల్ స్క్రీన్ అందుబాటులో లేదు"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"బ్యాటరీ సేవర్ ఆన్లో ఉన్నందున డ్యూయల్ స్క్రీన్ అందుబాటులో లేదు. మీరు దీన్ని సెట్టింగ్లలో ఆఫ్ చేయవచ్చు."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"సెట్టింగ్లకు వెళ్లండి"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ఆఫ్ చేయండి"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> కాన్ఫిగర్ చేయబడింది"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"కీబోర్డ్ లేఅవుట్ <xliff:g id="LAYOUT_1">%s</xliff:g>కు సెట్ చేయబడింది. మార్చడానికి ట్యాప్ చేయండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0b481f3..eef7772 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"การโทรผ่าน Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"การโทรผ่าน Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"ปิด"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"โทรผ่าน Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"โทรผ่านเครือข่ายมือถือ"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังใช้จอแสดงผลทั้งสองจอเพื่อแสดงเนื้อหา"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"อุปกรณ์ร้อนเกินไป"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"หน้าจอคู่ไม่พร้อมให้ใช้งานเนื่องจากโทรศัพท์ของคุณร้อนเกินไป"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen ใช้งานไม่ได้"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen ใช้งานไม่ได้เนื่องจากเปิดโหมดประหยัดแบตเตอรี่อยู่ คุณปิดโหมดนี้ได้ในการตั้งค่า"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ไปที่การตั้งค่า"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"ปิด"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"กำหนดค่า <xliff:g id="DEVICE_NAME">%s</xliff:g> แล้ว"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"ตั้งค่ารูปแบบแป้นพิมพ์เป็นภาษา<xliff:g id="LAYOUT_1">%s</xliff:g> แตะเพื่อเปลี่ยน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e7005db..d2137f6 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Pagtawag Gamit ang WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Tawag sa pamamagitan ng Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Naka-off"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Tumawag gamit ang Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Tumawag gamit ang mobile network"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"Ginagamit ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang parehong display para magpakita ng content"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Masyadong mainit ang device"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Hindi available ang Dual Screen dahil masyado nang umiinit ang telepono mo"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Hindi available ang Dual Screen"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Hindi available ang Dual Screen dahil naka-on ang Pantipid ng Baterya. Puwede mo itong i-off sa Mga Setting."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Pumunta sa Mga Setting"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"I-off"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Na-configure ang <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Naitakda ang layout ng keyboard sa <xliff:g id="LAYOUT_1">%s</xliff:g>. I-tap para baguhin."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 998b2fa..b2d7617 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Kablosuz"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Kablosuz Çağrı"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Kablosuz Çağrı"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Kapalı"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Kablosuz ağ üzerinden arama"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Mobil ağ üzerinden arama"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index be4b2a2e..9296f6a 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -142,8 +142,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Дзвінки через Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"Передавання голосу через Wi-Fi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Дзвінки через Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Вимкнено"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Телефонувати через Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Телефонувати через мобільну мережу"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 977374e..4970050 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> مواد دکھانے کیلئے دونوں ڈسپلیز استعمال کر رہی ہے"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"آلہ بہت زیادہ گرم ہے"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"دوہری اسکرین دستیاب نہیں ہے کیونکہ آپ کا فون بہت زیادہ گرم ہو رہا ہے"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Dual Screen دستیاب نہیں ہے"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Dual Screen دستیاب نہیں ہے کیونکہ بیٹری سیور آن ہے۔ آپ اسے ترتیبات میں آف کر سکتے ہیں۔"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"ترتیبات پر جائیں"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"آف کریں"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> میں کنفیگر کیا گیا"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"کی بورڈ لے آؤٹ <xliff:g id="LAYOUT_1">%s</xliff:g> پر سیٹ ہے۔ تبدیل کرنے کیلئے تھپتھپائیں۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 08b4471..69b2efb 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2324,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> kontentni ikkala ekranda chiqarmoqda"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Qurilma qizib ketdi"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Telefon qizib ketgani uchun hozir ikki ekranli rejim ishlamaydi"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Ikki ekranli rejim ishlamaydi"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Quvvatni tejash yoniqligi uchun hozir ikki ekranli rejim ishlamaydi. Buni Sozlamalarda faolsizlantirishingiz mumkin."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Sozlamalarni ochish"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Faolsizlantirish"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> sozlandi"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Klaviatura terilmasi bunga sozlandi: <xliff:g id="LAYOUT_1">%s</xliff:g>. Oʻzgartirish uchun ustiga bosing."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 29acdc0..93907f9 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Gọi qua Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Cuộc gọi qua Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Tắt"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Gọi qua Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Gọi qua mạng di động"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang dùng cả hai màn hình để thể hiện nội dung"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Thiết bị quá nóng"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"Không bật được chế độ Màn hình đôi vì điện thoại của bạn quá nóng"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Không bật được chế độ Dual Screen"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Không bật được chế độ Dual Screen vì Trình tiết kiệm pin đang bật. Bạn có thể tắt Trình tiết kiệm pin trong phần Cài đặt."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Chuyển đến phần Cài đặt"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Tắt"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Đã định cấu hình <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Đã thiết lập bố cục bàn phím thành <xliff:g id="LAYOUT_1">%s</xliff:g>. Hãy nhấn để thay đổi."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 428531e..818f1ff 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"WLAN"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"WLAN 通话"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"WLAN 通话"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"已关闭"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"通过 WLAN 进行通话"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"通过移动网络进行通话"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"<xliff:g id="APP_NAME">%1$s</xliff:g>正在使用双屏幕显示内容"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"设备过热"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"手机过热,因此无法使用双屏幕功能"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"“双屏幕”功能不可用"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"省电模式已开启,因此“双屏幕”功能不可用。您可在“设置”中关闭此模式。"</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"前往“设置”"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"关闭"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"已配置“<xliff:g id="DEVICE_NAME">%s</xliff:g>”"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"键盘布局已设为<xliff:g id="LAYOUT_1">%s</xliff:g>。点按即可更改。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 0caf957..67db060 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi 通話"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi 通話"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"關閉"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"使用 Wi-Fi 通話"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"使用流動網絡通話"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 90d7e21..b3af8e3 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Wi-Fi 通話"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Wi-Fi 通話"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"關閉"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"透過 Wi-Fi 進行通話"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"透過行動網路進行通話"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 967d9ea..0f9bde7 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -140,8 +140,7 @@
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"I-Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Ukushaya kwe-WiFi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
- <!-- no translation found for wfcSpnFormat_wifi_call (434016592539090004) -->
- <skip />
+ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Ikholi ye-Wi-Fi"</string>
<string name="wifi_calling_off_summary" msgid="5626710010766902560">"Valiwe"</string>
<string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Ikholi esebenza nge-Wi-Fi"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Shaya ngenethiwekhi yeselula"</string>
@@ -2325,12 +2324,9 @@
<string name="concurrent_display_notification_active_content" msgid="5889355473710601270">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> isebenzisa zombili izibonisi ukukhombisa okuqukethwe"</string>
<string name="concurrent_display_notification_thermal_title" msgid="5921609404644739229">"Idivayisi ifudumele kakhulu"</string>
<string name="concurrent_display_notification_thermal_content" msgid="2075484836527609319">"I-Dual Screen ayitholakali ngoba ifoni yakho iqala ukufudumala kakhulu"</string>
- <!-- no translation found for concurrent_display_notification_power_save_title (1794569070730736281) -->
- <skip />
- <!-- no translation found for concurrent_display_notification_power_save_content (2198116070583851493) -->
- <skip />
- <!-- no translation found for device_state_notification_settings_button (691937505741872749) -->
- <skip />
+ <string name="concurrent_display_notification_power_save_title" msgid="1794569070730736281">"Isikrini Esikabili asitholakali"</string>
+ <string name="concurrent_display_notification_power_save_content" msgid="2198116070583851493">"Isikrini Esikabili asitholakali ngoba Isilondolozi Sebhethri sivuliwe. Ungavala lokhu Kumasethingi."</string>
+ <string name="device_state_notification_settings_button" msgid="691937505741872749">"Iya Kumasethingi"</string>
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Vala"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"I-<xliff:g id="DEVICE_NAME">%s</xliff:g> ilungiselelwe"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Isakhiwo sekhibhodi sisethelwe ku-<xliff:g id="LAYOUT_1">%s</xliff:g>. Thepha ukushintsha."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0600b380..5a35ca7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2895,6 +2895,9 @@
mirror the content of the default display. -->
<bool name="config_localDisplaysMirrorContent">true</bool>
+ <!-- When true, udfps vote is ignored. This feature is disabled by default. -->
+ <bool name="config_ignoreUdfpsVote">false</bool>
+
<!-- Controls if local secondary displays should be private or not. Value specified in the array
represents physical port address of each display and display in this list will be marked
as private. {@see android.view.Display#FLAG_PRIVATE} -->
@@ -5582,10 +5585,20 @@
split screen. -->
<bool name="config_isWindowManagerCameraCompatTreatmentEnabled">false</bool>
+ <!-- Whether should use split screen aspect ratio for the activity when camera compat treatment
+ is enabled and activity is connected to the camera in fullscreen. -->
+ <bool name="config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled">false</bool>
+
<!-- Whether a camera compat controller is enabled to allow the user to apply or revert
treatment for stretched issues in camera viewfinder. -->
<bool name="config_isCameraCompatControlForStretchedIssuesEnabled">false</bool>
+ <!-- Docking is a uiMode configuration change and will cause activities to relaunch if it's not
+ handled. If true, the configuration change will be sent but activities will not be
+ relaunched upon docking. Apps with desk resources will behave like normal, since they may
+ expect the relaunch upon the desk uiMode change. -->
+ <bool name="config_skipActivityRelaunchWhenDocking">false</bool>
+
<!-- If true, hide the display cutout with display area -->
<bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 53e2b3a..8fb7c9d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -414,6 +414,7 @@
<java-symbol type="bool" name="config_guestUserAutoCreated" />
<java-symbol type="bool" name="config_guestUserAllowEphemeralStateChange" />
<java-symbol type="bool" name="config_localDisplaysMirrorContent" />
+ <java-symbol type="bool" name="config_ignoreUdfpsVote" />
<java-symbol type="array" name="config_localPrivateDisplayPorts" />
<java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
<java-symbol type="bool" name="config_enableAppWidgetService" />
@@ -4500,7 +4501,9 @@
<java-symbol type="bool" name="config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled" />
<java-symbol type="bool" name="config_isCompatFakeFocusEnabled" />
<java-symbol type="bool" name="config_isWindowManagerCameraCompatTreatmentEnabled" />
+ <java-symbol type="bool" name="config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled" />
<java-symbol type="bool" name="config_isCameraCompatControlForStretchedIssuesEnabled" />
+ <java-symbol type="bool" name="config_skipActivityRelaunchWhenDocking" />
<java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 6debbfe..c5b00c9 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -16,7 +16,6 @@
package android.app;
-import static android.app.Notification.Builder.ensureColorSpanContrast;
import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_READ;
import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_REPLY;
import static android.app.Notification.CarExtender.UnreadConversation.KEY_REMOTE_INPUT;
@@ -66,7 +65,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.LocusId;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -436,93 +434,7 @@
assertThat(Notification.Builder.getFullLengthSpanColor(text)).isEqualTo(expectedTextColor);
}
- @Test
- public void testBuilder_ensureColorSpanContrast_removesAllFullLengthColorSpans() {
- Spannable text = new SpannableString("blue text with yellow and green");
- text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(),
- Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext,
- R.style.TextAppearance_DeviceDefault_Notification_Title);
- assertThat(taSpan.getTextColor()).isNotNull(); // it must be set to prove it is cleared.
- text.setSpan(taSpan, 0, text.length(),
- Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- Spannable result = (Spannable) ensureColorSpanContrast(text, Color.BLACK);
- Object[] spans = result.getSpans(0, result.length(), Object.class);
- assertThat(spans).hasLength(3);
- assertThat(result.getSpanStart(spans[0])).isEqualTo(15);
- assertThat(result.getSpanEnd(spans[0])).isEqualTo(21);
- assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW);
-
- assertThat(result.getSpanStart(spans[1])).isEqualTo(0);
- assertThat(result.getSpanEnd(spans[1])).isEqualTo(31);
- assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span
- assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily());
- assertThat(((TextAppearanceSpan) spans[1]).getTextColor()).isNull();
-
- assertThat(result.getSpanStart(spans[2])).isEqualTo(26);
- assertThat(result.getSpanEnd(spans[2])).isEqualTo(31);
- assertThat(((ForegroundColorSpan) spans[2]).getForegroundColor()).isEqualTo(Color.GREEN);
- }
-
- @Test
- public void testBuilder_ensureColorSpanContrast_partialLength_adjusted() {
- int background = 0xFFFF0101; // Slightly lighter red
- CharSequence text = new SpannableStringBuilder()
- .append("text with ")
- .append("some red", new ForegroundColorSpan(Color.RED),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- CharSequence result = ensureColorSpanContrast(text, background);
-
- // ensure the span has been updated to have > 1.3:1 contrast ratio with fill color
- Object[] spans = ((Spannable) result).getSpans(0, result.length(), Object.class);
- assertThat(spans).hasLength(1);
- int foregroundColor = ((ForegroundColorSpan) spans[0]).getForegroundColor();
- assertContrastIsWithinRange(foregroundColor, background, 3, 3.2);
- }
-
- @Test
- public void testBuilder_ensureColorSpanContrast_worksWithComplexInput() {
- Spannable text = new SpannableString("blue text with yellow and green and cyan");
- text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(),
- Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- // cyan TextAppearanceSpan
- TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext,
- R.style.TextAppearance_DeviceDefault_Notification_Title);
- taSpan = new TextAppearanceSpan(taSpan.getFamily(), taSpan.getTextStyle(),
- taSpan.getTextSize(), ColorStateList.valueOf(Color.CYAN), null);
- text.setSpan(taSpan, 36, 40,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- Spannable result = (Spannable) ensureColorSpanContrast(text, Color.GRAY);
- Object[] spans = result.getSpans(0, result.length(), Object.class);
- assertThat(spans).hasLength(3);
-
- assertThat(result.getSpanStart(spans[0])).isEqualTo(15);
- assertThat(result.getSpanEnd(spans[0])).isEqualTo(21);
- assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW);
-
- assertThat(result.getSpanStart(spans[1])).isEqualTo(36);
- assertThat(result.getSpanEnd(spans[1])).isEqualTo(40);
- assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span
- assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily());
- ColorStateList newCyanList = ((TextAppearanceSpan) spans[1]).getTextColor();
- assertThat(newCyanList).isNotNull();
- assertContrastIsWithinRange(newCyanList.getDefaultColor(), Color.GRAY, 3, 3.2);
-
- assertThat(result.getSpanStart(spans[2])).isEqualTo(26);
- assertThat(result.getSpanEnd(spans[2])).isEqualTo(31);
- int newGreen = ((ForegroundColorSpan) spans[2]).getForegroundColor();
- assertThat(newGreen).isNotEqualTo(Color.GREEN);
- assertContrastIsWithinRange(newGreen, Color.GRAY, 3, 3.2);
- }
@Test
public void testBuilder_ensureButtonFillContrast_adjustsDarker() {
diff --git a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
index cfe660c..5f5bf11 100644
--- a/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/ContrastColorUtilTest.java
@@ -20,14 +20,35 @@
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Color;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.TextAppearanceSpan;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
+
import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+
public class ContrastColorUtilTest extends TestCase {
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
@SmallTest
public void testEnsureTextContrastAgainstDark() {
int darkBg = 0xFF35302A;
@@ -70,6 +91,91 @@
assertContrastIsWithinRange(selfContrastColor, lightBg, 4.5, 4.75);
}
+ public void testBuilder_ensureColorSpanContrast_removesAllFullLengthColorSpans() {
+ Spannable text = new SpannableString("blue text with yellow and green");
+ text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(),
+ Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext,
+ R.style.TextAppearance_DeviceDefault_Notification_Title);
+ assertThat(taSpan.getTextColor()).isNotNull(); // it must be set to prove it is cleared.
+ text.setSpan(taSpan, 0, text.length(),
+ Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ Spannable result = (Spannable) ContrastColorUtil.ensureColorSpanContrast(text, Color.BLACK);
+ Object[] spans = result.getSpans(0, result.length(), Object.class);
+ assertThat(spans).hasLength(3);
+
+ assertThat(result.getSpanStart(spans[0])).isEqualTo(15);
+ assertThat(result.getSpanEnd(spans[0])).isEqualTo(21);
+ assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW);
+
+ assertThat(result.getSpanStart(spans[1])).isEqualTo(0);
+ assertThat(result.getSpanEnd(spans[1])).isEqualTo(31);
+ assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span
+ assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily());
+ assertThat(((TextAppearanceSpan) spans[1]).getTextColor()).isNull();
+
+ assertThat(result.getSpanStart(spans[2])).isEqualTo(26);
+ assertThat(result.getSpanEnd(spans[2])).isEqualTo(31);
+ assertThat(((ForegroundColorSpan) spans[2]).getForegroundColor()).isEqualTo(Color.GREEN);
+ }
+
+ public void testBuilder_ensureColorSpanContrast_partialLength_adjusted() {
+ int background = 0xFFFF0101; // Slightly lighter red
+ CharSequence text = new SpannableStringBuilder()
+ .append("text with ")
+ .append("some red", new ForegroundColorSpan(Color.RED),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ CharSequence result = ContrastColorUtil.ensureColorSpanContrast(text, background);
+
+ // ensure the span has been updated to have > 1.3:1 contrast ratio with fill color
+ Object[] spans = ((Spannable) result).getSpans(0, result.length(), Object.class);
+ assertThat(spans).hasLength(1);
+ int foregroundColor = ((ForegroundColorSpan) spans[0]).getForegroundColor();
+ assertContrastIsWithinRange(foregroundColor, background, 3, 3.2);
+ }
+
+ public void testBuilder_ensureColorSpanContrast_worksWithComplexInput() {
+ Spannable text = new SpannableString("blue text with yellow and green and cyan");
+ text.setSpan(new ForegroundColorSpan(Color.YELLOW), 15, 21,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new ForegroundColorSpan(Color.BLUE), 0, text.length(),
+ Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ // cyan TextAppearanceSpan
+ TextAppearanceSpan taSpan = new TextAppearanceSpan(mContext,
+ R.style.TextAppearance_DeviceDefault_Notification_Title);
+ taSpan = new TextAppearanceSpan(taSpan.getFamily(), taSpan.getTextStyle(),
+ taSpan.getTextSize(), ColorStateList.valueOf(Color.CYAN), null);
+ text.setSpan(taSpan, 36, 40,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new ForegroundColorSpan(Color.GREEN), 26, 31,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ Spannable result = (Spannable) ContrastColorUtil.ensureColorSpanContrast(text, Color.GRAY);
+ Object[] spans = result.getSpans(0, result.length(), Object.class);
+ assertThat(spans).hasLength(3);
+
+ assertThat(result.getSpanStart(spans[0])).isEqualTo(15);
+ assertThat(result.getSpanEnd(spans[0])).isEqualTo(21);
+ assertThat(((ForegroundColorSpan) spans[0]).getForegroundColor()).isEqualTo(Color.YELLOW);
+
+ assertThat(result.getSpanStart(spans[1])).isEqualTo(36);
+ assertThat(result.getSpanEnd(spans[1])).isEqualTo(40);
+ assertThat(spans[1]).isNotSameInstanceAs(taSpan); // don't mutate the existing span
+ assertThat(((TextAppearanceSpan) spans[1]).getFamily()).isEqualTo(taSpan.getFamily());
+ ColorStateList newCyanList = ((TextAppearanceSpan) spans[1]).getTextColor();
+ assertThat(newCyanList).isNotNull();
+ assertContrastIsWithinRange(newCyanList.getDefaultColor(), Color.GRAY, 3, 3.2);
+
+ assertThat(result.getSpanStart(spans[2])).isEqualTo(26);
+ assertThat(result.getSpanEnd(spans[2])).isEqualTo(31);
+ int newGreen = ((ForegroundColorSpan) spans[2]).getForegroundColor();
+ assertThat(newGreen).isNotEqualTo(Color.GREEN);
+ assertContrastIsWithinRange(newGreen, Color.GRAY, 3, 3.2);
+ }
+
public static void assertContrastIsWithinRange(int foreground, int background,
double minContrast, double maxContrast) {
assertContrastIsAtLeast(foreground, background, minContrast);
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6328b02..2c85fe4 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -160,6 +160,7 @@
<assign-permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" uid="media" />
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="media" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="media" />
+ <assign-permission name="android.permission.LOG_FOREGROUND_RESOURCE_USE" uid="media" />
<assign-permission name="android.permission.INTERNET" uid="media" />
@@ -173,6 +174,7 @@
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="audioserver" />
<assign-permission name="android.permission.OBSERVE_SENSOR_PRIVACY" uid="audioserver" />
+ <assign-permission name="android.permission.LOG_FOREGROUND_RESOURCE_USE" uid="audioserver" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="cameraserver" />
@@ -186,6 +188,7 @@
<assign-permission name="android.permission.MANAGE_APP_OPS_MODES" uid="cameraserver" />
<assign-permission name="android.permission.OBSERVE_SENSOR_PRIVACY" uid="cameraserver" />
<assign-permission name="android.permission.REAL_GET_TASKS" uid="cameraserver" />
+ <assign-permission name="android.permission.LOG_FOREGROUND_RESOURCE_USE" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index dcc12ac..7fc8310e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -214,7 +214,8 @@
openingWholeScreenBounds.union(target.screenSpaceBounds);
} else {
closingTargets.add(target);
- closingWholeScreenBounds.union(target.screenSpaceBounds);
+ // Union the start bounds since this may be the ClosingChanging animation.
+ closingWholeScreenBounds.union(target.startBounds);
}
}
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
index 8a89779..89654d0 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -24,7 +24,7 @@
<string name="pip_move" msgid="158770205886688553">"हलवा"</string>
<string name="pip_expand" msgid="1051966011679297308">"विस्तार करा"</string>
<string name="pip_collapse" msgid="3903295106641385962">"कोलॅप्स करा"</string>
- <string name="pip_edu_text" msgid="7930546669915337998">"नियंत्रणांसाठी "<annotation icon="home_icon">"होम"</annotation>" दोनदा दाबा"</string>
+ <string name="pip_edu_text" msgid="7930546669915337998">"नियंत्रणांसाठी "<annotation icon="home_icon">"होम"</annotation>" दोनदा प्रेस करा"</string>
<string name="a11y_pip_menu_entered" msgid="5106343214776801614">"चित्रात-चित्र मेनू."</string>
<string name="a11y_action_pip_move_left" msgid="6612980937817141583">"डावीकडे हलवा"</string>
<string name="a11y_action_pip_move_right" msgid="1119409122645529936">"उजवीकडे हलवा"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 1df6ecd..1e3d795 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -224,7 +224,7 @@
openingWholeScreenBounds.union(change.getEndAbsBounds());
} else {
closingChanges.add(change);
- closingWholeScreenBounds.union(change.getEndAbsBounds());
+ closingWholeScreenBounds.union(change.getStartAbsBounds());
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
index 902c41c..4e10ce8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java
@@ -156,15 +156,13 @@
void setDontShowReachabilityEducationAgain(TaskInfo taskInfo) {
mCompatUISharedPreferences.edit().putBoolean(
- getDontShowAgainReachabilityEduKey(taskInfo.userId,
- taskInfo.topActivity.getPackageName()), true).apply();
+ getDontShowAgainReachabilityEduKey(taskInfo.userId), true).apply();
}
boolean shouldShowReachabilityEducation(@NonNull TaskInfo taskInfo) {
return getHasSeenLetterboxEducation(taskInfo.userId)
&& !mCompatUISharedPreferences.getBoolean(
- getDontShowAgainReachabilityEduKey(taskInfo.userId,
- taskInfo.topActivity.getPackageName()), /* default= */false);
+ getDontShowAgainReachabilityEduKey(taskInfo.userId), /* default= */false);
}
boolean getHasSeenLetterboxEducation(int userId) {
@@ -206,8 +204,8 @@
}
}
- private static String getDontShowAgainReachabilityEduKey(int userId, String packageName) {
- return HAS_SEEN_REACHABILITY_EDUCATION_KEY_PREFIX + "_" + packageName + "@" + userId;
+ private static String getDontShowAgainReachabilityEduKey(int userId) {
+ return HAS_SEEN_REACHABILITY_EDUCATION_KEY_PREFIX + "@" + userId;
}
private static String getDontShowLetterboxEduKey(int userId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index eb7c32f..f8743ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -54,6 +54,7 @@
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.desktopmode.DesktopTasksController;
+import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -676,12 +677,20 @@
SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
Transitions transitions,
+ EnterDesktopTaskTransitionHandler transitionHandler,
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
@ShellMainThread ShellExecutor mainExecutor
) {
return new DesktopTasksController(context, shellInit, shellController, displayController,
shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, transitions,
- desktopModeTaskRepository, mainExecutor);
+ transitionHandler, desktopModeTaskRepository, mainExecutor);
+ }
+
+ @WMSingleton
+ @Provides
+ static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler(
+ Transitions transitions) {
+ return new EnterDesktopTaskTransitionHandler(transitions);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index ad334b5..2bdbde1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -312,6 +312,20 @@
}
/**
+ * Moves a specifc task to the front.
+ * @param taskInfo the task to show in front.
+ */
+ public void moveTaskToFront(RunningTaskInfo taskInfo) {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reorder(taskInfo.token, true /* onTop */);
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ mTransitions.startTransition(TRANSIT_TO_FRONT, wct, null);
+ } else {
+ mShellTaskOrganizer.applyTransaction(wct);
+ }
+ }
+
+ /**
* Turn desktop mode on or off
* @param active the desired state for desktop mode setting
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 5696dfc..cb04a43 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -25,6 +25,7 @@
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.app.WindowConfiguration.WindowingMode
import android.content.Context
+import android.graphics.Rect
import android.os.IBinder
import android.os.SystemProperties
import android.view.SurfaceControl
@@ -67,6 +68,7 @@
private val syncQueue: SyncTransactionQueue,
private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
private val transitions: Transitions,
+ private val animationTransitionHandler: EnterDesktopTaskTransitionHandler,
private val desktopModeTaskRepository: DesktopModeTaskRepository,
@ShellMainThread private val mainExecutor: ShellExecutor
) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler {
@@ -133,6 +135,44 @@
}
}
+ /**
+ * Moves a single task to freeform and sets the taskBounds to the passed in bounds,
+ * startBounds
+ */
+ fun moveToFreeform(
+ taskInfo: RunningTaskInfo,
+ startBounds: Rect
+ ) {
+ val wct = WindowContainerTransaction()
+ moveHomeTaskToFront(wct)
+ addMoveToDesktopChanges(wct, taskInfo.getToken())
+ wct.setBounds(taskInfo.token, startBounds)
+
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ animationTransitionHandler.startTransition(
+ Transitions.TRANSIT_ENTER_FREEFORM, wct)
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
+ /** Brings apps to front and sets freeform task bounds */
+ fun moveToDesktopWithAnimation(
+ taskInfo: RunningTaskInfo,
+ freeformBounds: Rect
+ ) {
+ val wct = WindowContainerTransaction()
+ bringDesktopAppsToFront(wct)
+ addMoveToDesktopChanges(wct, taskInfo.getToken())
+ wct.setBounds(taskInfo.token, freeformBounds)
+
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ animationTransitionHandler.startTransition(Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct)
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
/** Move a task with given `taskId` to fullscreen */
fun moveToFullscreen(taskId: Int) {
shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToFullscreen(task) }
@@ -151,6 +191,17 @@
}
}
+ /** Move a task to the front **/
+ fun moveTaskToFront(taskInfo: ActivityManager.RunningTaskInfo) {
+ val wct = WindowContainerTransaction()
+ wct.reorder(taskInfo.token, true)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */)
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
/**
* Get windowing move for a given `taskId`
*
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
new file mode 100644
index 0000000..3df2340
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.transition.Transitions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * The {@link Transitions.TransitionHandler} that handles transitions for desktop mode tasks
+ * entering and exiting freeform.
+ */
+public class EnterDesktopTaskTransitionHandler implements Transitions.TransitionHandler {
+
+ private final Transitions mTransitions;
+ private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
+
+ // The size of the screen during drag relative to the fullscreen size
+ public static final float DRAG_FREEFORM_SCALE = 0.4f;
+ // The size of the screen after drag relative to the fullscreen size
+ public static final float FINAL_FREEFORM_SCALE = 0.6f;
+ public static final int FREEFORM_ANIMATION_DURATION = 336;
+
+ private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
+
+ public EnterDesktopTaskTransitionHandler(
+ Transitions transitions) {
+ this(transitions, SurfaceControl.Transaction::new);
+ }
+
+ public EnterDesktopTaskTransitionHandler(
+ Transitions transitions,
+ Supplier<SurfaceControl.Transaction> supplier) {
+ mTransitions = transitions;
+ mTransactionSupplier = supplier;
+ }
+
+ /**
+ * Starts Transition of a given type
+ * @param type Transition type
+ * @param wct WindowContainerTransaction for transition
+ */
+ public void startTransition(@WindowManager.TransitionType int type,
+ @NonNull WindowContainerTransaction wct) {
+ final IBinder token = mTransitions.startTransition(type, wct, this);
+ mPendingTransitionTokens.add(token);
+ }
+
+ @Override
+ public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ boolean transitionHandled = false;
+ for (TransitionInfo.Change change : info.getChanges()) {
+ if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
+ continue;
+ }
+
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ if (taskInfo == null || taskInfo.taskId == -1) {
+ continue;
+ }
+
+ if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
+ transitionHandled |= startChangeTransition(
+ transition, info.getType(), change, startT, finishCallback);
+ }
+ }
+
+ mPendingTransitionTokens.remove(transition);
+
+ return transitionHandled;
+ }
+
+ private boolean startChangeTransition(
+ @NonNull IBinder transition,
+ @WindowManager.TransitionType int type,
+ @NonNull TransitionInfo.Change change,
+ @NonNull SurfaceControl.Transaction startT,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ if (!mPendingTransitionTokens.contains(transition)) {
+ return false;
+ }
+
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ if (type == Transitions.TRANSIT_ENTER_FREEFORM
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+ // Transitioning to freeform but keeping fullscreen bounds, so the crop is set
+ // to null and we don't require an animation
+ final SurfaceControl sc = change.getLeash();
+ startT.setWindowCrop(sc, null);
+ startT.apply();
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
+ return true;
+ }
+
+ Rect endBounds = change.getEndAbsBounds();
+ if (type == Transitions.TRANSIT_ENTER_DESKTOP_MODE
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+ && !endBounds.isEmpty()) {
+ // This Transition animates a task to freeform bounds after being dragged into freeform
+ // mode and brings the remaining freeform tasks to front
+ final SurfaceControl sc = change.getLeash();
+ startT.setWindowCrop(sc, endBounds.width(),
+ endBounds.height());
+ startT.apply();
+
+ // We want to find the scale of the current bounds relative to the end bounds. The
+ // task is currently scaled to DRAG_FREEFORM_SCALE and the final bounds will be
+ // scaled to FINAL_FREEFORM_SCALE. So, it is scaled to
+ // DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE relative to the freeform bounds
+ final ValueAnimator animator =
+ ValueAnimator.ofFloat(DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE, 1f);
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ animator.addUpdateListener(animation -> {
+ final float animationValue = (float) animation.getAnimatedValue();
+ t.setScale(sc, animationValue, animationValue);
+
+ final float animationWidth = endBounds.width() * animationValue;
+ final float animationHeight = endBounds.height() * animationValue;
+ final int animationX = endBounds.centerX() - (int) (animationWidth / 2);
+ final int animationY = endBounds.centerY() - (int) (animationHeight / 2);
+
+ t.setPosition(sc, animationX, animationY);
+ t.apply();
+ });
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
+ }
+ });
+
+ animator.start();
+ return true;
+ }
+
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+ @NonNull TransitionRequestInfo request) {
+ return null;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index 60e5ff2..e1a56a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -112,6 +112,7 @@
onChangeTransitionReady(change, startT, finishT);
break;
}
+ mWindowDecorViewModel.onTransitionReady(transition, info, change);
}
mTransitionToTaskInfo.put(transition, taskInfoList);
}
@@ -168,6 +169,8 @@
} else {
mTransitionToTaskInfo.put(playing, infoOfMerged);
}
+
+ mWindowDecorViewModel.onTransitionMerged(merged, playing);
}
@Override
@@ -175,7 +178,7 @@
final List<ActivityManager.RunningTaskInfo> taskInfo =
mTransitionToTaskInfo.getOrDefault(transition, Collections.emptyList());
mTransitionToTaskInfo.remove(transition);
-
+ mWindowDecorViewModel.onTransitionFinished(transition);
for (int i = 0; i < taskInfo.size(); ++i) {
mWindowDecorViewModel.destroyWindowDecoration(taskInfo.get(i));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 1187126..4c53f60 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -210,7 +210,7 @@
/**
* Quietly cancel the animator by removing the listeners first.
*/
- public static void quietCancel(@NonNull ValueAnimator animator) {
+ static void quietCancel(@NonNull ValueAnimator animator) {
animator.removeAllUpdateListeners();
animator.removeAllListeners();
animator.cancel();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index c19d543..c5fc879 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -145,10 +145,12 @@
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
new PipAnimationController.PipAnimationCallback() {
+ private boolean mIsCancelled;
@Override
public void onPipAnimationStart(TaskInfo taskInfo,
PipAnimationController.PipTransitionAnimator animator) {
final int direction = animator.getTransitionDirection();
+ mIsCancelled = false;
sendOnPipTransitionStarted(direction);
}
@@ -156,6 +158,10 @@
public void onPipAnimationEnd(TaskInfo taskInfo, SurfaceControl.Transaction tx,
PipAnimationController.PipTransitionAnimator animator) {
final int direction = animator.getTransitionDirection();
+ if (mIsCancelled) {
+ sendOnPipTransitionFinished(direction);
+ return;
+ }
final int animationType = animator.getAnimationType();
final Rect destinationBounds = animator.getDestinationBounds();
if (isInPipDirection(direction) && animator.getContentOverlayLeash() != null) {
@@ -194,6 +200,7 @@
public void onPipAnimationCancel(TaskInfo taskInfo,
PipAnimationController.PipTransitionAnimator animator) {
final int direction = animator.getTransitionDirection();
+ mIsCancelled = true;
if (isInPipDirection(direction) && animator.getContentOverlayLeash() != null) {
fadeOutAndRemoveOverlay(animator.getContentOverlayLeash(),
animator::clearContentOverlay, true /* withStartDelay */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 582616d..463ad77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -783,7 +783,7 @@
mPipAnimationController.getCurrentAnimator();
if (animator != null && animator.isRunning()) {
// cancel any running animator, as it is using stale display layout information
- PipAnimationController.quietCancel(animator);
+ animator.cancel();
}
onDisplayChangedUncheck(layout, saveRestoreSnapFraction);
}
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 b8b6d5b..beabf18 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
@@ -19,6 +19,7 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_SLEEP;
@@ -133,6 +134,12 @@
/** Transition type for maximize to freeform transition. */
public static final int TRANSIT_RESTORE_FROM_MAXIMIZE = WindowManager.TRANSIT_FIRST_CUSTOM + 9;
+ /** Transition type to freeform in desktop mode. */
+ public static final int TRANSIT_ENTER_FREEFORM = WindowManager.TRANSIT_FIRST_CUSTOM + 10;
+
+ /** Transition type to freeform in desktop mode. */
+ public static final int TRANSIT_ENTER_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 11;
+
private final WindowOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
@@ -541,9 +548,7 @@
}
}
- // Allow to notify keyguard un-occluding state to KeyguardService, which can happen while
- // screen-off, so there might no visibility change involved.
- if (info.getRootCount() == 0 && info.getType() != TRANSIT_KEYGUARD_UNOCCLUDE) {
+ if (info.getRootCount() == 0 && !alwaysReportToKeyguard(info)) {
// No root-leashes implies that the transition is empty/no-op, so just do
// housekeeping and return.
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "No transition roots (%s): %s",
@@ -589,6 +594,23 @@
processReadyQueue();
}
+ /**
+ * Some transitions we always need to report to keyguard even if they are empty.
+ * TODO (b/274954192): Remove this once keyguard dispatching moves to Shell.
+ */
+ private static boolean alwaysReportToKeyguard(TransitionInfo info) {
+ // occlusion status of activities can change while screen is off so there will be no
+ // visibility change but we still need keyguardservice to be notified.
+ if (info.getType() == TRANSIT_KEYGUARD_UNOCCLUDE) return true;
+
+ // It's possible for some activities to stop with bad timing (esp. since we can't yet
+ // queue activity transitions initiated by apps) that results in an empty transition for
+ // keyguard going-away. In general, we should should always report Keyguard-going-away.
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) return true;
+
+ return false;
+ }
+
void processReadyQueue() {
if (mReadyTransitions.isEmpty()) {
// Check if idle.
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 6b7ca42..8e8faca 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
@@ -23,11 +23,13 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.os.Handler;
+import android.os.IBinder;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
+import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -72,6 +74,16 @@
}
@Override
+ public void onTransitionReady(IBinder transition, TransitionInfo info,
+ TransitionInfo.Change change) {}
+
+ @Override
+ public void onTransitionMerged(IBinder merged, IBinder playing) {}
+
+ @Override
+ public void onTransitionFinished(IBinder transition) {}
+
+ @Override
public void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter) {
mTaskOperations = new TaskOperations(transitionStarter, mContext, mSyncQueue);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 317b9a3..f943e52 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -22,7 +22,11 @@
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.DRAG_FREEFORM_SCALE;
+import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
+import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION;
+import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
@@ -30,6 +34,7 @@
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.util.SparseArray;
import android.view.Choreographer;
@@ -39,9 +44,13 @@
import android.view.InputMonitor;
import android.view.MotionEvent;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import android.view.View;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
import android.window.WindowContainerToken;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
@@ -54,8 +63,10 @@
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
+import java.util.function.Supplier;
/**
* View model for the window decoration with a caption and shadows. Works with
@@ -83,9 +94,20 @@
private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
private final InputMonitorFactory mInputMonitorFactory;
private TaskOperations mTaskOperations;
+ private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
private Optional<SplitScreenController> mSplitScreenController;
+ private ValueAnimator mDragToDesktopValueAnimator;
+ private final Rect mDragToDesktopAnimationStartBounds = new Rect();
+ private boolean mDragToDesktopAnimationStarted;
+ private float mCaptionDragStartX;
+
+ // These values keep track of any transitions to freeform to stop relayout from running on
+ // changing task so that shellTransitions has a chance to animate the transition
+ private int mPauseRelayoutForTask = -1;
+ private IBinder mTransitionPausingRelayout;
+
public DesktopModeWindowDecorViewModel(
Context context,
Handler mainHandler,
@@ -107,7 +129,8 @@
desktopTasksController,
splitScreenController,
new DesktopModeWindowDecoration.Factory(),
- new InputMonitorFactory());
+ new InputMonitorFactory(),
+ SurfaceControl.Transaction::new);
}
@VisibleForTesting
@@ -122,7 +145,8 @@
Optional<DesktopTasksController> desktopTasksController,
Optional<SplitScreenController> splitScreenController,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
- InputMonitorFactory inputMonitorFactory) {
+ InputMonitorFactory inputMonitorFactory,
+ Supplier<SurfaceControl.Transaction> transactionFactory) {
mContext = context;
mMainHandler = mainHandler;
mMainChoreographer = mainChoreographer;
@@ -136,6 +160,7 @@
mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
mInputMonitorFactory = inputMonitorFactory;
+ mTransactionFactory = transactionFactory;
}
@Override
@@ -155,6 +180,31 @@
}
@Override
+ public void onTransitionReady(
+ @NonNull IBinder transition,
+ @NonNull TransitionInfo info,
+ @NonNull TransitionInfo.Change change) {
+ if (change.getMode() == WindowManager.TRANSIT_CHANGE
+ && info.getType() == Transitions.TRANSIT_ENTER_DESKTOP_MODE) {
+ mTransitionPausingRelayout = transition;
+ }
+ }
+
+ @Override
+ public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
+ if (mTransitionPausingRelayout.equals(merged)) {
+ mTransitionPausingRelayout = playing;
+ }
+ }
+
+ @Override
+ public void onTransitionFinished(@NonNull IBinder transition) {
+ if (transition.equals(mTransitionPausingRelayout)) {
+ mPauseRelayoutForTask = -1;
+ }
+ }
+
+ @Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (decoration == null) return;
@@ -165,7 +215,12 @@
incrementEventReceiverTasks(taskInfo.displayId);
}
- decoration.relayout(taskInfo);
+ // TaskListener callbacks and shell transitions aren't synchronized, so starting a shell
+ // transition can trigger an onTaskInfoChanged call that updates the task's SurfaceControl
+ // and interferes with the transition animation that is playing at the same time.
+ if (taskInfo.taskId != mPauseRelayoutForTask) {
+ decoration.relayout(taskInfo);
+ }
}
@Override
@@ -252,6 +307,7 @@
} else if (id == R.id.back_button) {
mTaskOperations.injectBackKey();
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
+ moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
decoration.createHandleMenu();
} else if (id == R.id.desktop_button) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
@@ -272,9 +328,17 @@
if (id != R.id.caption_handle && id != R.id.desktop_mode_caption) {
return false;
}
+ moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
return mDragDetector.onMotionEvent(e);
}
+ private void moveTaskToFront(RunningTaskInfo taskInfo) {
+ if (!taskInfo.isFocused) {
+ mDesktopTasksController.ifPresent(c -> c.moveTaskToFront(taskInfo));
+ mDesktopModeController.ifPresent(c -> c.moveTaskToFront(taskInfo));
+ }
+ }
+
/**
* @param e {@link MotionEvent} to process
* @return {@code true} if the motion event is handled.
@@ -295,7 +359,8 @@
case MotionEvent.ACTION_DOWN: {
mDragPointerId = e.getPointerId(0);
mDragPositioningCallback.onDragPositioningStart(
- 0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
+ 0 /* ctrlType */, e.getRawX(0),
+ e.getRawY(0));
mIsDragging = false;
return false;
}
@@ -403,7 +468,8 @@
final DesktopModeWindowDecoration relevantDecor = getRelevantWindowDecor(ev);
if (DesktopModeStatus.isProto2Enabled()) {
if (relevantDecor == null
- || relevantDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
+ || relevantDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM
+ || mTransitionDragActive) {
handleCaptionThroughStatusBar(ev, relevantDecor);
}
}
@@ -444,8 +510,11 @@
DesktopModeWindowDecoration relevantDecor) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
+ mCaptionDragStartX = ev.getX();
// Begin drag through status bar if applicable.
if (relevantDecor != null) {
+ mDragToDesktopAnimationStartBounds.set(
+ relevantDecor.mTaskInfo.configuration.windowConfiguration.getBounds());
boolean dragFromStatusBarAllowed = false;
if (DesktopModeStatus.isProto2Enabled()) {
// In proto2 any full screen task can be dragged to freeform
@@ -461,33 +530,105 @@
}
case MotionEvent.ACTION_UP: {
if (relevantDecor == null) {
+ mDragToDesktopAnimationStarted = false;
mTransitionDragActive = false;
return;
}
if (mTransitionDragActive) {
mTransitionDragActive = false;
- final int statusBarHeight = mDisplayController
- .getDisplayLayout(relevantDecor.mTaskInfo.displayId).stableInsets().top;
+ final int statusBarHeight = getStatusBarHeight(
+ relevantDecor.mTaskInfo.displayId);
if (ev.getY() > statusBarHeight) {
if (DesktopModeStatus.isProto2Enabled()) {
+ mPauseRelayoutForTask = relevantDecor.mTaskInfo.taskId;
mDesktopTasksController.ifPresent(
- c -> c.moveToDesktop(relevantDecor.mTaskInfo));
+ c -> c.moveToDesktopWithAnimation(relevantDecor.mTaskInfo,
+ getFreeformBounds(ev)));
} else if (DesktopModeStatus.isProto1Enabled()) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
}
-
+ mDragToDesktopAnimationStarted = false;
+ return;
+ } else if (mDragToDesktopAnimationStarted) {
+ mDesktopTasksController.ifPresent(c ->
+ c.moveToFullscreen(relevantDecor.mTaskInfo));
+ mDragToDesktopAnimationStarted = false;
return;
}
}
relevantDecor.checkClickEvent(ev);
break;
}
+
+ case MotionEvent.ACTION_MOVE: {
+ if (relevantDecor == null) {
+ return;
+ }
+ if (mTransitionDragActive) {
+ final int statusBarHeight = mDisplayController
+ .getDisplayLayout(
+ relevantDecor.mTaskInfo.displayId).stableInsets().top;
+ if (ev.getY() > statusBarHeight) {
+ if (!mDragToDesktopAnimationStarted) {
+ mDragToDesktopAnimationStarted = true;
+ mDesktopTasksController.ifPresent(
+ c -> c.moveToFreeform(relevantDecor.mTaskInfo,
+ mDragToDesktopAnimationStartBounds));
+ startAnimation(relevantDecor);
+ }
+ }
+ if (mDragToDesktopAnimationStarted) {
+ Transaction t = mTransactionFactory.get();
+ float width = (float) mDragToDesktopValueAnimator.getAnimatedValue()
+ * mDragToDesktopAnimationStartBounds.width();
+ float x = ev.getX() - (width / 2);
+ t.setPosition(relevantDecor.mTaskSurface, x, ev.getY());
+ t.apply();
+ }
+ }
+ break;
+ }
+
case MotionEvent.ACTION_CANCEL: {
mTransitionDragActive = false;
+ mDragToDesktopAnimationStarted = false;
}
}
}
+ private Rect getFreeformBounds(@NonNull MotionEvent ev) {
+ final Rect endBounds = new Rect();
+ final int finalWidth = (int) (FINAL_FREEFORM_SCALE
+ * mDragToDesktopAnimationStartBounds.width());
+ final int finalHeight = (int) (FINAL_FREEFORM_SCALE
+ * mDragToDesktopAnimationStartBounds.height());
+
+ endBounds.left = mDragToDesktopAnimationStartBounds.centerX() - finalWidth / 2
+ + (int) (ev.getX() - mCaptionDragStartX);
+ endBounds.right = endBounds.left + (int) (FINAL_FREEFORM_SCALE
+ * mDragToDesktopAnimationStartBounds.width());
+ endBounds.top = (int) (ev.getY()
+ - ((FINAL_FREEFORM_SCALE - DRAG_FREEFORM_SCALE)
+ * mDragToDesktopAnimationStartBounds.height() / 2));
+ endBounds.bottom = endBounds.top + finalHeight;
+
+ return endBounds;
+ }
+
+ private void startAnimation(@NonNull DesktopModeWindowDecoration focusedDecor) {
+ mDragToDesktopValueAnimator = ValueAnimator.ofFloat(1f, DRAG_FREEFORM_SCALE);
+ mDragToDesktopValueAnimator.setDuration(FREEFORM_ANIMATION_DURATION);
+ final Transaction t = mTransactionFactory.get();
+ mDragToDesktopValueAnimator.addUpdateListener(animation -> {
+ final float animatorValue = (float) animation.getAnimatedValue();
+ SurfaceControl sc = focusedDecor.mTaskSurface;
+ t.setScale(sc, animatorValue, animatorValue);
+ t.apply();
+ });
+
+ mDragToDesktopValueAnimator.start();
+ }
+
@Nullable
private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
if (mSplitScreenController.isPresent()
@@ -534,6 +675,10 @@
return focusedDecor;
}
+ private int getStatusBarHeight(int displayId) {
+ return mDisplayController.getDisplayLayout(displayId).stableInsets().top;
+ }
+
private void createInputChannel(int displayId) {
final InputManager inputManager = mContext.getSystemService(InputManager.class);
final InputMonitor inputMonitor =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index 3734487..9f03d9a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -17,7 +17,9 @@
package com.android.wm.shell.windowdecor;
import android.app.ActivityManager;
+import android.os.IBinder;
import android.view.SurfaceControl;
+import android.window.TransitionInfo;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
@@ -95,4 +97,34 @@
* @param taskInfo the info of the task
*/
void destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo);
+
+ /**
+ * Notifies that a shell transition is about to start. If the transition is of type
+ * TRANSIT_ENTER_DESKTOP, it will save that transition to unpause relayout for the transitioning
+ * task after the transition has ended.
+ *
+ * @param transition the ready transaction
+ * @param info of Transition to check if relayout needs to be paused for a task
+ * @param change a change in the given transition
+ */
+ default void onTransitionReady(IBinder transition, TransitionInfo info,
+ TransitionInfo.Change change) {}
+
+ /**
+ * Notifies that a shell transition is about to merge with another to give the window
+ * decoration a chance to prepare for this merge.
+ *
+ * @param merged the transaction being merged
+ * @param playing the transaction being merged into
+ */
+ default void onTransitionMerged(IBinder merged, IBinder playing) {}
+
+ /**
+ * Notifies that a shell transition is about to finish to give the window decoration a chance
+ * to clean up.
+ *
+ * @param transaction
+ */
+ default void onTransitionFinished(IBinder transaction) {}
+
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TransitionInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TransitionInfoBuilder.java
index 26b787f..a658375 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TransitionInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TransitionInfoBuilder.java
@@ -38,8 +38,15 @@
public TransitionInfoBuilder(@WindowManager.TransitionType int type,
@WindowManager.TransitionFlags int flags) {
+ this(type, flags, false /* asNoOp */);
+ }
+
+ public TransitionInfoBuilder(@WindowManager.TransitionType int type,
+ @WindowManager.TransitionFlags int flags, boolean asNoOp) {
mInfo = new TransitionInfo(type, flags);
- mInfo.addRootLeash(DISPLAY_ID, createMockSurface(true /* valid */), 0, 0);
+ if (!asNoOp) {
+ mInfo.addRootLeash(DISPLAY_ID, createMockSurface(true /* valid */), 0, 0);
+ }
}
public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
index 3f79df6..12ceb0a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java
@@ -66,6 +66,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.HashSet;
+import java.util.Set;
import java.util.function.Consumer;
/**
@@ -118,6 +120,18 @@
mExecutor = new TestShellExecutor();
mCompatUIConfiguration = new CompatUIConfiguration(mContext, mExecutor) {
+ final Set<Integer> mHasSeenSet = new HashSet<>();
+
+ @Override
+ boolean getHasSeenLetterboxEducation(int userId) {
+ return mHasSeenSet.contains(userId);
+ }
+
+ @Override
+ void setSeenLetterboxEducation(int userId) {
+ mHasSeenSet.add(userId);
+ }
+
@Override
protected String getCompatUISharedPreferenceName() {
return TEST_COMPAT_UI_SHARED_PREFERENCES;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 5cad50d..4ccc467 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -81,6 +81,7 @@
@Mock lateinit var syncQueue: SyncTransactionQueue
@Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
@Mock lateinit var transitions: Transitions
+ @Mock lateinit var transitionHandler: EnterDesktopTaskTransitionHandler
lateinit var mockitoSession: StaticMockitoSession
lateinit var controller: DesktopTasksController
@@ -116,6 +117,7 @@
syncQueue,
rootTaskDisplayAreaOrganizer,
transitions,
+ transitionHandler,
desktopModeTaskRepository,
TestShellExecutor()
)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
new file mode 100644
index 0000000..6199e0b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
+import static androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.WindowConfiguration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.IWindowContainerToken;
+import android.window.TransitionInfo;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.transition.Transitions;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Supplier;
+
+/** Tests of {@link com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler} */
+@SmallTest
+public class EnterDesktopTaskTransitionHandlerTest {
+
+ @Mock
+ private Transitions mTransitions;
+ @Mock
+ IBinder mToken;
+ @Mock
+ Supplier<SurfaceControl.Transaction> mTransactionFactory;
+ @Mock
+ SurfaceControl.Transaction mStartT;
+ @Mock
+ SurfaceControl.Transaction mFinishT;
+ @Mock
+ SurfaceControl.Transaction mAnimationT;
+ @Mock
+ Transitions.TransitionFinishCallback mTransitionFinishCallback;
+ @Mock
+ ShellExecutor mExecutor;
+ @Mock
+ SurfaceControl mSurfaceControl;
+
+ private EnterDesktopTaskTransitionHandler mEnterDesktopTaskTransitionHandler;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ doReturn(mExecutor).when(mTransitions).getMainExecutor();
+ doReturn(mAnimationT).when(mTransactionFactory).get();
+
+ mEnterDesktopTaskTransitionHandler = new EnterDesktopTaskTransitionHandler(mTransitions,
+ mTransactionFactory);
+ }
+
+ @Test
+ public void testEnterFreeformAnimation() {
+ final int transitionType = Transitions.TRANSIT_ENTER_FREEFORM;
+ final int taskId = 1;
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ doReturn(mToken).when(mTransitions)
+ .startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+
+ TransitionInfo.Change change =
+ createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
+ TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_ENTER_FREEFORM, change);
+
+
+ assertTrue(mEnterDesktopTaskTransitionHandler
+ .startAnimation(mToken, info, mStartT, mFinishT, mTransitionFinishCallback));
+
+ verify(mStartT).setWindowCrop(mSurfaceControl, null);
+ verify(mStartT).apply();
+ }
+
+ @Test
+ public void testTransitEnterDesktopModeAnimation() throws Throwable {
+ final int transitionType = Transitions.TRANSIT_ENTER_DESKTOP_MODE;
+ final int taskId = 1;
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ doReturn(mToken).when(mTransitions)
+ .startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+
+ TransitionInfo.Change change =
+ createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
+ change.setEndAbsBounds(new Rect(0, 0, 1, 1));
+ TransitionInfo info = createTransitionInfo(Transitions.TRANSIT_ENTER_DESKTOP_MODE, change);
+
+ runOnUiThread(() -> {
+ try {
+ assertTrue(mEnterDesktopTaskTransitionHandler
+ .startAnimation(mToken, info, mStartT, mFinishT,
+ mTransitionFinishCallback));
+ } catch (Exception e) {
+ throw new AssertionFailedError(e.getMessage());
+ }
+ });
+
+ verify(mStartT).setWindowCrop(mSurfaceControl, change.getEndAbsBounds().width(),
+ change.getEndAbsBounds().height());
+ verify(mStartT).apply();
+ }
+
+ private TransitionInfo.Change createChange(@WindowManager.TransitionType int type, int taskId,
+ @WindowConfiguration.WindowingMode int windowingMode) {
+ final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.taskId = taskId;
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+ final TransitionInfo.Change change = new TransitionInfo.Change(
+ new WindowContainerToken(mock(IWindowContainerToken.class)), mSurfaceControl);
+ change.setMode(type);
+ change.setTaskInfo(taskInfo);
+ return change;
+ }
+
+ private static TransitionInfo createTransitionInfo(
+ @WindowManager.TransitionType int type, @NonNull TransitionInfo.Change change) {
+ TransitionInfo info = new TransitionInfo(type, 0);
+ info.addChange(change);
+ return info;
+ }
+
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 44f1f01..60d6978 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -1039,6 +1039,25 @@
verify(observer, times(0)).onTransitionFinished(eq(transitToken3), anyBoolean());
}
+ @Test
+ public void testEmptyTransitionStillReportsKeyguardGoingAway() {
+ Transitions transitions = createTestTransitions();
+ transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+ IBinder transitToken = new Binder();
+ transitions.requestStartTransition(transitToken,
+ new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+
+ // Make a no-op transition
+ TransitionInfo info = new TransitionInfoBuilder(
+ TRANSIT_OPEN, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, true /* noOp */).build();
+ transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+
+ // If keyguard-going-away flag set, then it shouldn't be aborted.
+ assertEquals(1, mDefaultHandler.activeCount());
+ }
+
class ChangeBuilder {
final TransitionInfo.Change mChange;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 1d1aa79..9a90996 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -28,6 +28,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.WindowConfiguration;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.input.InputManager;
@@ -60,6 +61,7 @@
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
/** Tests of {@link DesktopModeWindowDecorViewModel} */
@SmallTest
@@ -80,8 +82,9 @@
@Mock private DesktopTasksController mDesktopTasksController;
@Mock private InputMonitor mInputMonitor;
@Mock private InputManager mInputManager;
-
@Mock private DesktopModeWindowDecorViewModel.InputMonitorFactory mMockInputMonitorFactory;
+ @Mock private Supplier<SurfaceControl.Transaction> mTransactionFactory;
+ @Mock private SurfaceControl.Transaction mTransaction;
private final List<InputManager> mMockInputManagers = new ArrayList<>();
private DesktopModeWindowDecorViewModel mDesktopModeWindowDecorViewModel;
@@ -102,12 +105,14 @@
Optional.of(mDesktopTasksController),
Optional.of(mSplitScreenController),
mDesktopModeWindowDecorFactory,
- mMockInputMonitorFactory
+ mMockInputMonitorFactory,
+ mTransactionFactory
);
doReturn(mDesktopModeWindowDecoration)
.when(mDesktopModeWindowDecorFactory)
.create(any(), any(), any(), any(), any(), any(), any(), any());
+ doReturn(mTransaction).when(mTransactionFactory).get();
when(mMockInputMonitorFactory.create(any(), any())).thenReturn(mInputMonitor);
// InputChannel cannot be mocked because it passes to InputEventReceiver.
@@ -250,7 +255,7 @@
}
private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId,
- int displayId, int windowingMode) {
+ int displayId, @WindowConfiguration.WindowingMode int windowingMode) {
ActivityManager.RunningTaskInfo taskInfo =
new TestRunningTaskInfoBuilder()
.setDisplayId(displayId)
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index db76390..ac1f92de 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -605,15 +605,25 @@
}
mPreviousPosition = bounds;
-#ifdef __ANDROID__ // Layoutlib does not support CanvasContext
- incStrong(0);
- auto functor = std::bind(
- std::mem_fn(&PositionListenerTrampoline::doUpdatePositionAsync), this,
- (jlong) info.canvasContext.getFrameNumber(),
- (jint) bounds.left, (jint) bounds.top,
- (jint) bounds.right, (jint) bounds.bottom);
+ ATRACE_NAME("Update SurfaceView position");
- info.canvasContext.enqueueFrameWork(std::move(functor));
+#ifdef __ANDROID__ // Layoutlib does not support CanvasContext
+ JNIEnv* env = jnienv();
+ // Update the new position synchronously. We cannot defer this to
+ // a worker pool to process asynchronously because the UI thread
+ // may be unblocked by the time a worker thread can process this,
+ // In particular if the app removes a view from the view tree before
+ // this callback is dispatched, then we lose the position
+ // information for this frame.
+ jboolean keepListening = env->CallStaticBooleanMethod(
+ gPositionListener.clazz, gPositionListener.callPositionChanged, mListener,
+ static_cast<jlong>(info.canvasContext.getFrameNumber()),
+ static_cast<jint>(bounds.left), static_cast<jint>(bounds.top),
+ static_cast<jint>(bounds.right), static_cast<jint>(bounds.bottom));
+ if (!keepListening) {
+ env->DeleteGlobalRef(mListener);
+ mListener = nullptr;
+ }
#endif
}
@@ -628,7 +638,14 @@
ATRACE_NAME("SurfaceView position lost");
JNIEnv* env = jnienv();
#ifdef __ANDROID__ // Layoutlib does not support CanvasContext
- // TODO: Remember why this is synchronous and then make a comment
+ // Update the lost position synchronously. We cannot defer this to
+ // a worker pool to process asynchronously because the UI thread
+ // may be unblocked by the time a worker thread can process this,
+ // In particular if a view's rendernode is readded to the scene
+ // before this callback is dispatched, then we report that we lost
+ // position information on the wrong frame, which can be problematic
+ // for views like SurfaceView which rely on RenderNode callbacks
+ // for driving visibility.
jboolean keepListening = env->CallStaticBooleanMethod(
gPositionListener.clazz, gPositionListener.callPositionLost, mListener,
info ? info->canvasContext.getFrameNumber() : 0);
@@ -708,23 +725,6 @@
}
}
- void doUpdatePositionAsync(jlong frameNumber, jint left, jint top,
- jint right, jint bottom) {
- ATRACE_NAME("Update SurfaceView position");
-
- JNIEnv* env = jnienv();
- jboolean keepListening = env->CallStaticBooleanMethod(
- gPositionListener.clazz, gPositionListener.callPositionChanged, mListener,
- frameNumber, left, top, right, bottom);
- if (!keepListening) {
- env->DeleteGlobalRef(mListener);
- mListener = nullptr;
- }
-
- // We need to release ourselves here
- decStrong(0);
- }
-
JavaVM* mVm;
jobject mListener;
uirenderer::Rect mPreviousPosition;
diff --git a/media/Android.bp b/media/Android.bp
index e8555b0..f69dd3c 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -29,10 +29,7 @@
},
},
srcs: [
- "aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl",
- "aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl",
- "aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl",
- "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
+ "aidl/android/media/soundtrigger_middleware/*.aidl",
],
imports: [
"android.media.audio.common.types-V2",
diff --git a/media/aidl/android/media/soundtrigger_middleware/IAcknowledgeEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/IAcknowledgeEvent.aidl
new file mode 100644
index 0000000..237e71a
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/IAcknowledgeEvent.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.soundtrigger_middleware;
+
+/**
+ * Opaque callback for acknowledging oneway events.
+ * Since there is no return channel for oneway events,
+ * passing this interface in a oneway method allows the service to call
+ * back to the client to indicate the event was registered.
+ * This essentially functions like a <code> Future<void> </code> without
+ * an error channel.
+ * {@hide}
+ */
+oneway interface IAcknowledgeEvent {
+ /**
+ * Acknowledge that the event has been received.
+ */
+ void eventReceived();
+
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/IInjectGlobalEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/IInjectGlobalEvent.aidl
new file mode 100644
index 0000000..dcf3945
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/IInjectGlobalEvent.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.soundtrigger_middleware;
+
+import android.media.soundtrigger_middleware.IAcknowledgeEvent;
+
+/**
+ * Interface for injecting global events to the fake STHAL.
+ * {@hide}
+ */
+oneway interface IInjectGlobalEvent {
+
+ /**
+ * Request a fake STHAL restart.
+ * This invalidates the {@link IInjectGlobalEvent}.
+ */
+ void triggerRestart();
+
+ /**
+ * Triggers global resource contention into the fake STHAL. Loads/startRecognition
+ * will fail with RESOURCE_CONTENTION.
+ * @param isContended - true to enable resource contention. false to disable resource contention
+ * and resume normal functionality.
+ * @param callback - Call {@link IAcknowledgeEvent#eventReceived()} on this interface once
+ * the contention status is successfully set.
+ */
+ void setResourceContention(boolean isContended, IAcknowledgeEvent callback);
+
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/IInjectModelEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/IInjectModelEvent.aidl
new file mode 100644
index 0000000..7752c17
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/IInjectModelEvent.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.soundtrigger_middleware;
+
+/**
+ * Interface for injecting model events into the fake ST HAL.
+ *
+ * {@hide}
+ */
+oneway interface IInjectModelEvent {
+ /**
+ * Trigger a preemptive model unload for the model session associated with
+ * this object.
+ * This invalidates the {@link IInjectModelEvent} session.
+ */
+ void triggerUnloadModel();
+
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/IInjectRecognitionEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/IInjectRecognitionEvent.aidl
new file mode 100644
index 0000000..f1398c6
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/IInjectRecognitionEvent.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.PhraseRecognitionExtra;
+
+/**
+ * Interface for injecting recognition events into the ST Mock HAL.
+ * {@hide}
+ */
+oneway interface IInjectRecognitionEvent {
+
+ /**
+ * Trigger a recognition event for the recognition session associated with
+ * this object.
+ * This invalidates the {@link IInjectRecognitionEvent}.
+ * @param data the recognition data that the client of this model will receive
+ * @param phraseExtras extra data only delivered for keyphrase models.
+ */
+ void triggerRecognitionEvent(in byte[] data,
+ in @nullable PhraseRecognitionExtra[] phraseExtras);
+
+ /**
+ * Trigger an abort event for the recognition session associated with this object.
+ * This invalidates the {@link IInjectRecognitionEvent}.
+ */
+ void triggerAbortRecognition();
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerInjection.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerInjection.aidl
new file mode 100644
index 0000000..732744b
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerInjection.aidl
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.Phrase;
+
+import android.media.soundtrigger_middleware.IInjectModelEvent;
+import android.media.soundtrigger_middleware.IInjectRecognitionEvent;
+import android.media.soundtrigger_middleware.IInjectGlobalEvent;
+import android.media.soundtrigger_middleware.ISoundTriggerInjection;
+
+/**
+ * An injection interface for {@link android.media.soundtrigger_middleware.FakeSoundTriggerHal}.
+ * To avoid deadlocks, all calls to this interface and the sub-interface it creates are oneway.
+ * Calls are identified as stale via "Session" parameters.
+ * The client implements this interface and registers it with
+ * {@link ISoundTriggerMiddlewareService#attachMockHalInjection(ISoundTriggerInjection)}.
+ * Then, the client will receive callbacks which observe mock HAL events.
+ * There are two types of calls.
+ * 1) Those that provide a new injection sub-interface (contains param .*Injection).
+ * 2) Those that are sessioned via an injection sub-interface (contains param .*Session).
+ * The new injection sub-interfaces generated by (1) can be used to trigger HAL events.
+ * Some calls within (2) will invalidate the session object which they are associated with
+ * (e.g. {@link soundModelUnloaded}), and will be noted as such.
+ * Some calls within the injection interface (e.g. {@link IInjectModelEvent#triggerUnloadModel()})
+ * will invalidate the session object they are called upon, and will be noted as such.
+ * @hide
+ */
+oneway interface ISoundTriggerInjection {
+
+ /**
+ * Value of {@link android.media.soundtrigger.Properties#supportedModelArch} that
+ * identifies the HAL as a fake HAL.
+ */
+ const String FAKE_HAL_ARCH = "injection";
+
+ /**
+ * Called following attachment via
+ * {@link ISoundTriggerMiddlewareService#attachMockHalInjection(ISoundTriggerInjection)}.
+ * Provides the client an injection interface for events which are always (globally) valid.
+ * @param globalInjection - Interface used to inject global events to the fake HAL.
+ * Used as a session object for further callbacks associated with the HAL globally.
+ */
+ void registerGlobalEventInjection(IInjectGlobalEvent globalInjection);
+
+ /**
+ * Called when the HAL has been restarted by the framework. Not called after a
+ * {@link IInjectGlobalEvent#triggerRestart()}.
+ * @param globalSession - The interface previously provided by a
+ * {@link registerGlobalEventInjection} call which this restart is associated with.
+ * Used to disambiguate stale restart events from a subsequent global session.
+ */
+ void onRestarted(IInjectGlobalEvent globalSession);
+
+ /**
+ * Called when the HAL has been detached by the framework.
+ * @param globalSession - The interface previously provided by a
+ * {@link registerGlobalEventInjection} call which this detach is associated with.
+ * Used to disambiguate stale detach events from a subsequent global session.
+ */
+ void onFrameworkDetached(IInjectGlobalEvent globalSession);
+
+ /**
+ * Called when a client is attached to the framework. This event is not actually
+ * delivered to the HAL, but is useful to understand the framework state.
+ * @param token - An opaque token representing the framework client session.
+ * Associated with a subsequent call to {@link onClientDetached(IBinder)}.
+ * @param globalSession - The global STHAL session this attach is associated with.
+ */
+ void onClientAttached(IBinder token, IInjectGlobalEvent globalSession);
+
+ /**
+ * Called when a client detaches from the framework. This event is not actually
+ * delivered to the HAL, but is useful to understand the framework state.
+ * @param token - The opaque token returned by a previous
+ * {@link onClientAttached(IBinder, IInjectGlobalEvent} call.
+ */
+ void onClientDetached(IBinder token);
+
+ /**
+ * Called when a sound model is loaded into the fake STHAL by the framework.
+ * @param model - The model data for the newly loaded model.
+ * @param phrases - The phrase data for the newly loaded model, if it is a keyphrase model.
+ * Null otherwise.
+ * @param modelInjection - Interface used to inject events associated with the newly loaded
+ * model into the fake STHAL.
+ * Used as a session object for further callbacks associated with this newly loaded model.
+ * @param globalSession - The session object representing the global STHAL instance this load
+ * is associated with.
+ */
+ void onSoundModelLoaded(in SoundModel model, in @nullable Phrase[] phrases,
+ IInjectModelEvent modelInjection, IInjectGlobalEvent globalSession);
+
+ /**
+ * Called when the fake STHAL receives a set parameter call from the framework on a previously
+ * loaded model.
+ * @param modelParam - Code of the parameter being set, see
+ * {@link android.media.soundtrigger.ModelParameter}
+ * @param value - Value to set the modelParam to
+ * @param modelSession - Session object of the loaded model the set param call is associated
+ * with.
+ */
+
+ void onParamSet(int modelParam, int value, IInjectModelEvent modelSession);
+
+
+ /**
+ * Called when a previously loaded model in the fake STHAL has recognition started by the
+ * framework.
+ * @param audioSessionToken - The audio session token passed by the framework which will be
+ * contained within a received recognition event.
+ * @param config - The recognition config passed by the framework for this recognition.
+ * @param recognitionInjection - A new injection interface which allows the client to
+ * trigger events associated with this newly started recognition.
+ * @param modelSession - The session object representing the loaded model that this
+ * recognition is associated with.
+ */
+ void onRecognitionStarted(int audioSessionToken, in RecognitionConfig config,
+ IInjectRecognitionEvent recognitionInjection, IInjectModelEvent modelSession);
+
+ /**
+ * Called when a previously started recognition in the fake STHAL is stopped by the framework.
+ * Not called following any calls on {@link IInjectRecognitionEvent}.
+ * @param recognitionSession - The session object received via a previous call to
+ * {@link recognitionStarted(int, RecognitionConfig, IInjectModelEvent,
+ * IInjectRecognitionEvent} which has been unloaded.
+ * This session is invalidated subsequent to this call, and no triggers will be respected.
+ */
+ void onRecognitionStopped(IInjectRecognitionEvent recognitionSession);
+
+ /**
+ * Called when a previously loaded model in the fake STHAL is unloaded by the framework.
+ * Not called following {@link IInjectModelEvent#triggerUnloadModel()}.
+ * @param modelSession - The session object received via a previous call to
+ * {@link soundModelLoaded(SoundModel, Phrase[], IInjectModelEvent} which has been unloaded.
+ * This session is invalidated subsequent to this call, and no triggers will be respected.
+ */
+ void onSoundModelUnloaded(IInjectModelEvent modelSession);
+
+ /**
+ * Called when this injection interface has been preempted by a subsequent call to
+ * {@link ISoundTriggerMiddleware#attachFakeHal(ISoundTriggerInjection)}.
+ * No more events will be delivered, and any further injection will be ignored.
+ */
+ void onPreempted();
+
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
index 0b46fd4..18688ce 100644
--- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media.soundtrigger_middleware;
import android.media.soundtrigger.ModelParameter;
@@ -148,4 +149,4 @@
* All models must have been unloaded prior to calling this method.
*/
void detach();
-}
\ No newline at end of file
+}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index bf264f8f..031c3ff 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -107,7 +107,7 @@
private final Map<OnMediaKeyEventSessionChangedListener, Executor>
mMediaKeyEventSessionChangedCallbacks = new HashMap<>();
@GuardedBy("mLock")
- private String mCurMediaKeyEventSessionPackage;
+ private String mCurMediaKeyEventSessionPackage = "";
@GuardedBy("mLock")
private MediaSession.Token mCurMediaKeyEventSession;
@GuardedBy("mLock")
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index d3f598a..253ade8 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -594,7 +594,7 @@
@Override
public void notifyRecordingScheduled(String recordingId, String requestId) {
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(
- DO_NOTIFY_RECORDING_SCHEDULED, recordingId, recordingId));
+ DO_NOTIFY_RECORDING_SCHEDULED, recordingId, requestId));
}
@Override
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index fc8fe5c..06d1acd 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -1420,7 +1420,7 @@
return;
}
try {
- mService.notifyRecordingScheduled(mToken, recordingId, recordingId, mUserId);
+ mService.notifyRecordingScheduled(mToken, recordingId, requestId, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/packages/CarrierDefaultApp/res/values-af/strings.xml b/packages/CarrierDefaultApp/res/values-af/strings.xml
index 64cc776..56dd89a 100644
--- a/packages/CarrierDefaultApp/res/values-af/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-af/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Diensverskafferkommunikasie"</string>
<string name="android_system_label" msgid="2797790869522345065">"Selfoondiensverskaffer"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobiele data is op"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Jou mobiele data is gedeaktiveer"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Byvoorbeeld, die aanmeldbladsy behoort dalk nie aan die organisasie wat gewys word nie."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Gaan in elk geval deur blaaier voort"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Prestasiehupstoot"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-opsies van jou diensverskaffer"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Besoek %s se webwerf om opsies vir jou appervaring te sien"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nie nou nie"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Bestuur"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Koop ’n prestasiehupstoot."</string>
diff --git a/packages/CarrierDefaultApp/res/values-am/strings.xml b/packages/CarrierDefaultApp/res/values-am/strings.xml
index 1bbc190..e626105 100644
--- a/packages/CarrierDefaultApp/res/values-am/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-am/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"የአገልግሎት አቅራቢ ግንኙነቶች"</string>
<string name="android_system_label" msgid="2797790869522345065">"የተንቀሳቃሽ ስልክ አገልግሎት አቅራቢ"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"የተንቀሳቃሽ ስልክ ውሂብ አልቋል"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"የእርስዎ የተንቀሳቃሽ ስልክ ውሂብ ቦዝኗል"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ለምሳሌ፣ የመግቢያ ገጹ የሚታየው ድርጅት ላይሆን ይችላል።"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ለማንኛውም በአሳሽ በኩል ይቀጥሉ"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"የአፈጻጸም ጭማሪ"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5ጂ አማራጮች ከአገልግሎት አቅራቢዎ"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ለመተግበሪያዎ ተሞክሮ አማራጮችን ለማየት የ%s ድር ጣቢያን ይጎብኙ"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"አሁን አይደለም"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"አስተዳድር"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"የአፈጻጸም ጭማሪ ይግዙ።"</string>
diff --git a/packages/CarrierDefaultApp/res/values-as/strings.xml b/packages/CarrierDefaultApp/res/values-as/strings.xml
index 56e2da5..860b82c 100644
--- a/packages/CarrierDefaultApp/res/values-as/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-as/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"বাহকৰ যোগাযোগ"</string>
<string name="android_system_label" msgid="2797790869522345065">"ম’বাইল সেৱা প্ৰদান কৰা কোম্পানী"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"ম’বাইল ডেটা শেষ হৈছে"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"আপোনাৰ ম’বাইল ডেটা সেৱা নিষ্ক্ৰিয় কৰা হৈছে"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"উদাহৰণস্বৰূপে, আপোনাক দেখুওৱা লগ ইনৰ পৃষ্ঠাটো প্ৰতিষ্ঠানটোৰ নিজা নহ\'বও পাৰে।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"তথাপিও ব্ৰাউজাৰৰ জৰিয়তে অব্যাহত ৰাখক"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"কাৰ্যক্ষমতা পৰিৱৰ্ধন"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"আপোনাৰ বাহকে আগবঢ়োৱা 5G বিকল্পসমূহ"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"আপোনাৰ এপৰ অভিজ্ঞতাৰ বাবে বিকল্পসমূহ চাবলৈ %sৰ ৱেবছাইটলৈ যাওক"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"এতিয়া নহয়"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"পৰিচালনা কৰক"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"এটা কাৰ্যক্ষমতা পৰিৱৰ্ধন ক্ৰয় কৰক।"</string>
diff --git a/packages/CarrierDefaultApp/res/values-az/strings.xml b/packages/CarrierDefaultApp/res/values-az/strings.xml
index 9677b62..5be5740 100644
--- a/packages/CarrierDefaultApp/res/values-az/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-az/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Operator Kommunikasiyaları"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobil Operator"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobil data bitib"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Mobil data deaktiv edilib"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Məsələn, giriş səhifəsi göstərilən təşkilata aid olmaya bilər."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Hər bir halda brazuer ilə davam edin"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performans artırması"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Operatorunuzdan 5G seçimləri"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Tətbiq təcrübəsi üzrə seçimlərə baxmaq üçün %s veb-saytına daxil olun"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"İndi yox"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"İdarə edin"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Performans artırması alın."</string>
diff --git a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
index fc16b14..3d2e480 100644
--- a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Obaveštenja mobilnog operatera"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobilni operater"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobilni podaci su potrošeni"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Mobilni podaci su deaktivirani"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Na primer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko pregledača"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Poboljšanje učinka"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G opcije mobilnog operatera"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Opcije za doživljaj aplikacije potražite na veb-sajtu mobilnog operatera %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sada"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljaj"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite poboljšanje učinka."</string>
diff --git a/packages/CarrierDefaultApp/res/values-bg/strings.xml b/packages/CarrierDefaultApp/res/values-bg/strings.xml
index 966ec33d..95bd04b 100644
--- a/packages/CarrierDefaultApp/res/values-bg/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bg/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Съобщения от оператора"</string>
<string name="android_system_label" msgid="2797790869522345065">"Мобилен оператор"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Мобилните данни са изразходвани"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Мобилните ви данни са деактивирани"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Например страницата за вход може да не принадлежи на показаната организация."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Продължаване през браузър въпреки това"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Увеличаване на ефективността"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Опции за 5G от оператора ви"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"За да видите опции за практическата си работа с приложението, посетете уебсайта на %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сега"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управление"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Купете пакет за увеличаване на ефективността."</string>
diff --git a/packages/CarrierDefaultApp/res/values-bn/strings.xml b/packages/CarrierDefaultApp/res/values-bn/strings.xml
index 46eeb74..516dd89 100644
--- a/packages/CarrierDefaultApp/res/values-bn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bn/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"পরিষেবা প্রদানকারীর সাথে যোগাযোগ"</string>
<string name="android_system_label" msgid="2797790869522345065">"পরিষেবা প্রদানকারী"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"মোবাইল ডেটা ফুরিয়ে গেছে"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"আপনার মোবাইল ডেটা নিষ্ক্রিয় করা হয়েছে"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"যেমন, লগ-ইন পৃষ্ঠাটি যে প্রতিষ্ঠানের পৃষ্ঠা বলে দেখানো আছে, আসলে তা নাও হতে পারে৷"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"যাই হোক, ব্রাউজারের মাধ্যমে চালিয়ে যান"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"পারফর্ম্যান্স বুস্ট"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"আপনার পরিষেবা প্রদানকারীর থেকে পাওয়া 5G বিকল্প"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"আপনার অ্যাপ সংক্রান্ত অভিজ্ঞতা উন্নত করার বিকল্পগুলি দেখতে, %s-এর ওয়েবসাইট ভিজিট করুন"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"এখন নয়"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ম্যানেজ করুন"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"পারফর্ম্যান্স বুস্ট সংক্রান্ত ফিচার কিনুন।"</string>
diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml
index d41ad21..61d8dc8 100644
--- a/packages/CarrierDefaultApp/res/values-bs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Komunikacije putem operatera"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobilni operater"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobilni internet je potrošen"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Prijenos podataka na mobilnoj mreži je deaktiviran"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Naprimjer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko preglednika"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Pojačavanje performansi"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opcije 5G mreže operatera"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Posjetite web lokaciju operatera %s da vidite opcije za iskustvo u aplikaciji"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sada"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljajte"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite pojačavanje performansi."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ca/strings.xml b/packages/CarrierDefaultApp/res/values-ca/strings.xml
index afde919..ec032d5 100644
--- a/packages/CarrierDefaultApp/res/values-ca/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ca/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Comunicacions de l\'operador"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operador de telefonia mòbil"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"S\'han esgotat les dades mòbils"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"S\'han desactivat les dades mòbils"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Per exemple, la pàgina d\'inici de sessió podria no pertànyer a l\'organització que es mostra."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continua igualment mitjançant el navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Optimització de rendiment"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opcions 5G del teu operador"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visita el lloc web de %s per veure les opcions relacionades amb la teva experiència a l\'aplicació"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ara no"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestiona"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Compra una optimització de rendiment."</string>
diff --git a/packages/CarrierDefaultApp/res/values-de/strings.xml b/packages/CarrierDefaultApp/res/values-de/strings.xml
index 65e2fd5..b4cdc56 100644
--- a/packages/CarrierDefaultApp/res/values-de/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-de/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Kommunikation mit Mobilfunkanbieter"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobilfunkanbieter"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobile Daten sind aufgebraucht"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Deine mobilen Daten wurden deaktiviert"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Trotzdem in einem Browser fortfahren"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Leistungs-Boost"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-Optionen von deinem Mobilfunkanbieter"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Besuche die Website von %s, um dir die Optionen für deine App anzusehen"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nicht jetzt"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Verwalten"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Leistungs-Boost erwerben."</string>
diff --git a/packages/CarrierDefaultApp/res/values-el/strings.xml b/packages/CarrierDefaultApp/res/values-el/strings.xml
index 7a55d3a..8a6430d 100644
--- a/packages/CarrierDefaultApp/res/values-el/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-el/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Επικοινωνίες εταιρείας κινητής τηλεφωνίας"</string>
<string name="android_system_label" msgid="2797790869522345065">"Εταιρεία κινητής τηλεφωνίας"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Τα δεδομένα κινητής τηλεφωνίας εξαντλήθηκαν"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Τα δεδομένα κινητής τηλεφωνίας έχουν απενεργοποιηθεί"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Για παράδειγμα, η σελίδα σύνδεσης ενδέχεται να μην ανήκει στον οργανισμό που εμφανίζεται."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Συνέχεια ούτως ή άλλως μέσω του προγράμματος περιήγησης"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Ενίσχυση απόδοσης"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Επιλογές 5G από την εταιρεία κινητής τηλεφωνίας σας"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Επισκεφτείτε τον ιστότοπο %s για να δείτε επιλογές για την εμπειρία της εφαρμογής σας"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Όχι τώρα"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Διαχείριση"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Αγοράστε μια ενίσχυση απόδοσης."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
index 9d6b013..1f20896 100644
--- a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Operator communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobile Operator"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobile data has run out"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Your mobile data has been deactivated"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G options from your operator"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visit %s\'s website to see options for your app experience"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
index 00c0357..c084a0a 100644
--- a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobile Carrier"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobile data has run out"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Your mobile data has been deactivated"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page may not belong to the organization shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G options from your carrier"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visit %s\'s website to see options for your app experience"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
index 9d6b013..1f20896 100644
--- a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Operator communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobile Operator"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobile data has run out"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Your mobile data has been deactivated"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G options from your operator"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visit %s\'s website to see options for your app experience"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
index 9d6b013..1f20896 100644
--- a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Operator communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobile Operator"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobile data has run out"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Your mobile data has been deactivated"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G options from your operator"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visit %s\'s website to see options for your app experience"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
index 7f7456d..0178925 100644
--- a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobile Carrier"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobile data has run out"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Your mobile data has been deactivated"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page may not belong to the organization shown."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Performance boost"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G options from your carrier"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visit %s\'s website to see options for your app experience"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Not now"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Manage"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Purchase a performance boost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
index 85598235..5bf0e6e 100644
--- a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Comunicaciones de operadores"</string>
<string name="android_system_label" msgid="2797790869522345065">"Compañía de telefonía móvil"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Se agotó el servicio de datos móviles"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Se desactivaron los datos móviles"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de acceso no pertenezca a la organización que aparece."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos desde el navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de rendimiento"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opciones de 5G de tu operador"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visita el sitio web de %s para ver opciones de tu experiencia en la app"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ahora no"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Administrar"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Compra un aumento de rendimiento."</string>
diff --git a/packages/CarrierDefaultApp/res/values-es/strings.xml b/packages/CarrierDefaultApp/res/values-es/strings.xml
index b9fa4c0..2a41c89 100644
--- a/packages/CarrierDefaultApp/res/values-es/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-es/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Comunicaciones del operador"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operador de telefonía móvil"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Se han agotado los datos móviles"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Se han desactivado los datos móviles"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de inicio de sesión no pertenezca a la organización mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos a través del navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Mejora de rendimiento"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opciones 5G de tu operador"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visita el sitio web de %s para ver opciones relacionadas con tu experiencia en la aplicación"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ahora no"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestionar"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar una mejora de rendimiento."</string>
diff --git a/packages/CarrierDefaultApp/res/values-et/strings.xml b/packages/CarrierDefaultApp/res/values-et/strings.xml
index e51b76c..c1a33d0 100644
--- a/packages/CarrierDefaultApp/res/values-et/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-et/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobiilioperaator"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobiilse andmeside limiit on täis"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Teie mobiilne andmeside on inaktiveeritud"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Näiteks ei pruugi sisselogimisleht kuuluda kuvatavale organisatsioonile."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Jätka siiski brauseris"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Jõudluse võimendus"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G valikud teie operaatorilt"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Külastage operaatori %s veebisaiti, et näha oma rakenduse kasutuskogemuse valikuid"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Mitte praegu"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Haldamine"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Ostke jõudluse võimendus."</string>
diff --git a/packages/CarrierDefaultApp/res/values-eu/strings.xml b/packages/CarrierDefaultApp/res/values-eu/strings.xml
index 3650635..86e1291 100644
--- a/packages/CarrierDefaultApp/res/values-eu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-eu/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Operadorearekiko komunikazioa"</string>
<string name="android_system_label" msgid="2797790869522345065">"Telefonia mugikorreko operadorea"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Agortu egin da datu-konexioa"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Desaktibatu da datu-konexioa"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Adibidez, baliteke saioa hasteko orria adierazitako erakundearena ez izatea."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Jarraitu arakatzailearen bidez, halere"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Errendimendu-hobekuntza"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Operadoreak eskaintzen dituen 5G-aren aukerak"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Joan %s operadorearen webgunera aplikazioaren erabileraren inguruko aukerak ikusteko"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Orain ez"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Kudeatu"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Erosi errendimendu-hobekuntza bat."</string>
diff --git a/packages/CarrierDefaultApp/res/values-fa/strings.xml b/packages/CarrierDefaultApp/res/values-fa/strings.xml
index 0738cbf..89c184c 100644
--- a/packages/CarrierDefaultApp/res/values-fa/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fa/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"ارتباطات شرکت مخابراتی"</string>
<string name="android_system_label" msgid="2797790869522345065">"شرکت مخابراتی دستگاه همراه"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"داده تلفن همراه تمام شده است"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"داده شبکه تلفن همراه شما غیرفعال شده است"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"به عنوان مثال، صفحه ورود به سیستم ممکن است متعلق به سازمان نشان داده شده نباشد."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"درهر صورت ازطریق مرورگر ادامه یابد"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"تقویتکننده عملکرد"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"گزینههای نسل پنجم شرکت مخابراتی شما"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"برای دیدن گزینههای مرتبط با تجربه برنامه، به وبسایت %s مراجعه کنید"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"اکنون نه"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"مدیریت"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"تقویتکننده عملکرد خریداری کنید."</string>
diff --git a/packages/CarrierDefaultApp/res/values-fr/strings.xml b/packages/CarrierDefaultApp/res/values-fr/strings.xml
index 1d06a1d..4bc03ffa 100644
--- a/packages/CarrierDefaultApp/res/values-fr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fr/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Opérateur des communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Opérateur mobile"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Les données mobiles sont épuisées"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Les données mobiles ont été désactivées pour votre compte"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion peut ne pas appartenir à l\'organisation représentée."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans le navigateur"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Boost de performances"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Options 5G de votre opérateur"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Accédez au site Web de %s pour consulter les options pour l\'expérience de votre appli"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Pas maintenant"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gérer"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Achetez un boost de performances."</string>
diff --git a/packages/CarrierDefaultApp/res/values-gu/strings.xml b/packages/CarrierDefaultApp/res/values-gu/strings.xml
index d003a44..1d42e8f 100644
--- a/packages/CarrierDefaultApp/res/values-gu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-gu/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"મોબાઇલ ઑપરેટર તરફથી કમ્યુનિકેશન"</string>
<string name="android_system_label" msgid="2797790869522345065">"મોબાઇલ કૅરિઅર"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"મોબાઇલ ડેટા પૂરો થઈ ગયો છે"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"તમારો મોબાઇલ ડેટા નિષ્ક્રિય કરવામાં આવ્યો છે"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ઉદાહરણ તરીકે, લોગિન પૃષ્ઠ બતાવવામાં આવેલી સંસ્થાનું ન પણ હોય."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"તો પણ બ્રાઉઝર મારફતે ચાલુ રાખો"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"પર્ફોર્મન્સ બૂસ્ટ"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"તમારા મોબાઇલ ઑપરેટર તરફથી 5G વિકલ્પો"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"તમારા ઍપ અનુભવ માટેના વિકલ્પો જોવા માટે %sની વેબસાઇટની મુલાકાત લો"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"હમણાં નહીં"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"મેનેજ કરો"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"પર્ફોર્મન્સ બૂસ્ટ ખરીદો."</string>
diff --git a/packages/CarrierDefaultApp/res/values-hi/strings.xml b/packages/CarrierDefaultApp/res/values-hi/strings.xml
index 6b3c544..a830d77 100644
--- a/packages/CarrierDefaultApp/res/values-hi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hi/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"मोबाइल सेवा देने वाली कंपनी"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"मोबाइल डेटा खत्म हो गया है"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"आपका मोबाइल डेटा बंद कर दिया गया है"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरण के लिए, हो सकता है कि लॉगिन पेज दिखाए गए संगठन का ना हो."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ब्राउज़र के ज़रिए किसी भी तरह जारी रखें"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"परफ़ॉर्मेंस बूस्ट"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी से मिले 5G के विकल्प"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ऐप्लिकेशन का बेहतर अनुभव पाने के लिए, %s की वेबसाइट पर जाकर विकल्प देखें"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"अभी नहीं"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"मैनेज करें"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"कोई परफ़ॉर्मेंस बूस्ट खरीदें."</string>
diff --git a/packages/CarrierDefaultApp/res/values-hr/strings.xml b/packages/CarrierDefaultApp/res/values-hr/strings.xml
index 1a58080..34bf601 100644
--- a/packages/CarrierDefaultApp/res/values-hr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hr/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Komunikacije operatera"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobilni operater"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobilni su podaci potrošeni"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Mobilni su podaci deaktivirani"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Na primjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi putem preglednika"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Poboljšanje izvedbe"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opcije 5G mreže vašeg operatera"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Posjetite web-lokaciju %s za prikaz opcija za doživljaj aplikacije"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne sad"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljajte"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite poboljšanje izvedbe."</string>
diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml
index 6ed1efe..13ac0a16 100644
--- a/packages/CarrierDefaultApp/res/values-hu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Szolgáltatói értesítések"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobilszolgáltató"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Elérte a rendelkezésre álló mobiladat-mennyiséget"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"A rendszer deaktiválta a mobiladat-forgalmat"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Például lehetséges, hogy a bejelentkezési oldal nem a megjelenített szervezethez tartozik."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Folytatás ennek ellenére böngészőn keresztül"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Teljesítménynövelés"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-beállítások a szolgáltatótól"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"A(z) %s webhelyén megtekintheti az alkalmazás által nyújtott élményekhez tartozó beállításokat"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Most nem"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Kezelés"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Vásároljon teljesítménynövelést."</string>
diff --git a/packages/CarrierDefaultApp/res/values-in/strings.xml b/packages/CarrierDefaultApp/res/values-in/strings.xml
index cb0f35b..f9a9732 100644
--- a/packages/CarrierDefaultApp/res/values-in/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-in/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Komunikasi Operator"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operator Seluler"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Data seluler telah habis"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Data seluler telah dinonaktifkan"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Misalnya, halaman login mungkin bukan milik organisasi yang ditampilkan."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Tetap lanjutkan melalui browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Penguat sinyal"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opsi 5G dari operator Anda"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Buka situs %s untuk melihat opsi pengalaman aplikasi Anda"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Lain kali"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Kelola"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Beli penguat sinyal."</string>
diff --git a/packages/CarrierDefaultApp/res/values-is/strings.xml b/packages/CarrierDefaultApp/res/values-is/strings.xml
index 1e5fa78..ca9d6c7 100644
--- a/packages/CarrierDefaultApp/res/values-is/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-is/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Samskipti við símafyrirtæki"</string>
<string name="android_system_label" msgid="2797790869522345065">"Símafyrirtæki"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Farsímagögn kláruðust"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Slökkt hefur verið á farsímagögnum"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Til dæmis getur verið að innskráningarsíðan tilheyri ekki fyrirtækinu sem birtist."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Halda samt áfram í vafra"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Afkastaaukning"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-valkostir frá símafyrirtækinu"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Opnaðu vefsvæði %s til að sjá valkosti varðandi upplifun í forritinu"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ekki núna"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Stjórna"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kaupa afkastaaukningu."</string>
diff --git a/packages/CarrierDefaultApp/res/values-iw/strings.xml b/packages/CarrierDefaultApp/res/values-iw/strings.xml
index 3551acf..9e5a8b5 100644
--- a/packages/CarrierDefaultApp/res/values-iw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-iw/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"מידע מהספק"</string>
<string name="android_system_label" msgid="2797790869522345065">"ספק שירות לנייד"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"ניצלת את מכסת הנתונים הסלולריים"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"חבילת הגלישה שלך הושבתה"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"לדוגמה, ייתכן שדף ההתחברות אינו שייך לארגון המוצג."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"המשך בכל זאת באמצעות דפדפן"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"שיפור ביצועים"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"אפשרויות של רשת 5G מהספק"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ניתן להיכנס לאתר של %s כדי לראות אפשרויות נוספות לחוויית השימוש באפליקציה"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"לא עכשיו"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ניהול"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"רכישת שיפור ביצועים."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ka/strings.xml b/packages/CarrierDefaultApp/res/values-ka/strings.xml
index ee281d7..4488a55 100644
--- a/packages/CarrierDefaultApp/res/values-ka/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ka/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"ოპერატორთან კომუნიკაცია"</string>
<string name="android_system_label" msgid="2797790869522345065">"მობილური ოპერატორი"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"მობილური ინტერნეტის პაკეტი ამოიწურა"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"მობილური ინტერნეტი დეაქტივირებულია"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"მაგალითად, სისტემაში შესვლის გვერდი შეიძლება არ ეკუთვნოდეს ნაჩვენებ ორგანიზაციას."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"მაინც ბრაუზერში გაგრძელება"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ეფექტურობის გაძლიერება"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G ვარიანტები თქვენი ოპერატორისგან"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ეწვიეთ %s-ის ვებსაიტს თქვენი აპის გამოცდილების ვარიანტების სანახავად"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ახლა არა"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"მართვა"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ეფექტურობის გაძლიერების შეძენა."</string>
diff --git a/packages/CarrierDefaultApp/res/values-kk/strings.xml b/packages/CarrierDefaultApp/res/values-kk/strings.xml
index b5f6950..ad91c79 100644
--- a/packages/CarrierDefaultApp/res/values-kk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-kk/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Оператор байланыстары"</string>
<string name="android_system_label" msgid="2797790869522345065">"Мобильдік байланыс операторы"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Мобильдік интернет бітті"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Мобильдік интернет өшірілді"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Мысалы, кіру беті көрсетілген ұйымға тиесілі болмауы мүмкін."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Бәрібір браузер арқылы жалғастыру"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Өнімділікті арттыру"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Оператор ұсынған 5G опциялары"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Қолданбаның жұмысына арналған опцияларды көру үшін %s веб-сайтына кіріңіз."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Қазір емес"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Басқару"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Өнімділікті арттыру құралын сатып алыңыз."</string>
diff --git a/packages/CarrierDefaultApp/res/values-km/strings.xml b/packages/CarrierDefaultApp/res/values-km/strings.xml
index 20199a7..1852489 100644
--- a/packages/CarrierDefaultApp/res/values-km/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-km/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"ទំនាក់ទំនងរបស់ក្រុមហ៊ុនសេវាទូរសព្ទ"</string>
<string name="android_system_label" msgid="2797790869522345065">"ក្រុមហ៊ុនបម្រើសេវាទូរសព្ទចល័ត"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"ទិន្នន័យចល័តបានអស់ហើយ"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"ទិន្នន័យចល័តរបស់អ្នកត្រូវបានបិទដំណើរការហើយ"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ឧទាហរណ៍៖ ទំព័រចូលនេះអាចនឹងមិនមែនជាកម្មសិទ្ធិរបស់ស្ថាប័នដែលបានបង្ហាញនេះទេ។"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"យ៉ាងណាក៏ដោយនៅតែបន្តតាមរយៈកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ការបង្កើនប្រតិបត្តិការ"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"ជម្រើស 5G ពីក្រុមហ៊ុនសេវាទូរសព្ទរបស់អ្នក"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ចូលទៅកាន់គេហទំព័ររបស់ %s ដើម្បីមើលជម្រើសសម្រាប់បទពិសោធន៍ប្រើកម្មវិធីរបស់អ្នក"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"កុំទាន់"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"គ្រប់គ្រង"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ទិញការបង្កើនប្រតិបត្តិការ។"</string>
diff --git a/packages/CarrierDefaultApp/res/values-kn/strings.xml b/packages/CarrierDefaultApp/res/values-kn/strings.xml
index 619b92a..bc3e1cc 100644
--- a/packages/CarrierDefaultApp/res/values-kn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-kn/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"ವಾಹಕ ಸಂವಹನಗಳು"</string>
<string name="android_system_label" msgid="2797790869522345065">"ಮೊಬೈಲ್ ವಾಹಕ"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"ಮೊಬೈಲ್ ಡೇಟಾ ಮುಗಿದುಹೋಗಿದೆ"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"ನಿಮ್ಮ ಮೊಬೈಲ್ ಡೇಟಾ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ಉದಾಹರಣೆಗೆ, ಲಾಗಿನ್ ಪುಟವು ತೋರಿಸಲಾಗಿರುವ ಸಂಸ್ಥೆಗೆ ಸಂಬಂಧಿಸಿಲ್ಲದಿರಬಹುದು."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ಪರವಾಗಿಲ್ಲ, ಬ್ರೌಸರ್ ಮೂಲಕ ಮುಂದುವರಿಸಿ"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ಕಾರ್ಯಕ್ಷಮತೆ ಬೂಸ್ಟ್"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"ನಿಮ್ಮ ವಾಹಕದಿಂದ 5G ಆಯ್ಕೆಗಳು"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ನಿಮ್ಮ ಆ್ಯಪ್ ಅನುಭವಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ನೋಡಲು %s ನ ವೆಬ್ಸೈಟ್ಗೆ ಭೇಟಿ ನೀಡಿ"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ಈಗ ಬೇಡ"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ನಿರ್ವಹಿಸಿ"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ಕಾರ್ಯಕ್ಷಮತೆ ಬೂಸ್ಟ್ ಅನ್ನು ಖರೀದಿಸಿ."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ko/strings.xml b/packages/CarrierDefaultApp/res/values-ko/strings.xml
index 46e172d..4e82d25 100644
--- a/packages/CarrierDefaultApp/res/values-ko/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ko/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"이동통신사 커뮤니케이션"</string>
<string name="android_system_label" msgid="2797790869522345065">"이동통신사"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"모바일 데이터가 소진되었습니다."</string>
<string name="no_data_notification_id" msgid="668400731803969521">"모바일 데이터가 비활성화되었습니다."</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"예를 들어 로그인 페이지가 표시된 조직에 속하지 않을 수 있습니다."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"브라우저를 통해 계속하기"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"성능 향상"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"이동통신사의 5G 옵션"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"%s 웹사이트에 방문하여 앱 환경에 관한 옵션을 확인하세요."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"나중에"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"관리"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"성능 향상 구매"</string>
diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml
index f2a96bc..aa6a132 100644
--- a/packages/CarrierDefaultApp/res/values-ky/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Байланыш операторунун билдирмелери"</string>
<string name="android_system_label" msgid="2797790869522345065">"Мобилдик байланыш оператору"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Мобилдик Интернетиңиздин трафиги түгөндү"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Мобилдик Интернет өчүрүлгөн"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Мисалы, аккаунтка кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Баары бир серепчи аркылуу улантуу"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Иштин майнаптуулугун жогорулатуу"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Байланыш операторунун 5G варианттары"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Колдонмону иштетүү параметрлерин көрүү үчүн %s сайтына өтүңүз"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Азыр эмес"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Тескөө"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Иштин майнаптуулугун жогорулатууну сатып алыңыз."</string>
diff --git a/packages/CarrierDefaultApp/res/values-lo/strings.xml b/packages/CarrierDefaultApp/res/values-lo/strings.xml
index 28af830..0624c72 100644
--- a/packages/CarrierDefaultApp/res/values-lo/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lo/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"ການສື່ສານຈາກຜູ້ໃຫ້ບໍລິການ"</string>
<string name="android_system_label" msgid="2797790869522345065">"ຜູ້ໃຫ້ບໍລິການມືຖື"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"ອິນເຕີເນັດມືຖືໝົດແລ້ວ"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"ປິດການນຳໃຊ້ອິນເຕີເນັດມືຖືຂອງທ່ານແລ້ວ"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ຕົວຢ່າງ, ໜ້າເຂົ້າສູ່ລະບົບອາດຈະບໍ່ແມ່ນຂອງອົງກອນທີ່ປາກົດ."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ດຳເນີນການຕໍ່ຜ່ານໂປຣແກຣມທ່ອງເວັບ"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ເລັ່ງປະສິດທິພາບ"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"ຕົວເລືອກ 5G ຈາກຜູ້ໃຫ້ບໍລິການຂອງທ່ານ"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ເບິ່ງຕົວເລືອກຕ່າງໆສຳລັບປະສົບການການນຳໃຊ້ແອັບຂອງທ່ານໄດ້ຢູ່ເວັບໄຊຂອງ %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ບໍ່ຟ້າວເທື່ອ"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ຈັດການ"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ຊື້ການເລັ່ງປະສິດທິພາບ."</string>
diff --git a/packages/CarrierDefaultApp/res/values-lt/strings.xml b/packages/CarrierDefaultApp/res/values-lt/strings.xml
index b9be333..8780eb0 100644
--- a/packages/CarrierDefaultApp/res/values-lt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lt/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Operatoriaus pranešimai"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobiliojo ryšio operatorius"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobiliojo ryšio duomenys baigėsi"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Mobiliojo ryšio duomenys išaktyvinti"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Pavyzdžiui, prisijungimo puslapis gali nepriklausyti rodomai organizacijai."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vis tiek tęsti naudojant naršyklę"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Našumo pagerinimas"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Operatoriaus teikiamos 5G parinktys"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Apsilankykite „%s“ svetainėje ir peržiūrėkite programos funkcijų parinktis"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne dabar"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Tvarkyti"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Įsigykite našumo pagerinimo paslaugą."</string>
diff --git a/packages/CarrierDefaultApp/res/values-lv/strings.xml b/packages/CarrierDefaultApp/res/values-lv/strings.xml
index d539947..a65fa58 100644
--- a/packages/CarrierDefaultApp/res/values-lv/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lv/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Paziņojumi no mobilo sakaru operatora"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobilo sakaru operators"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Sasniegts mobilo datu ierobežojums."</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Jūsu mobilie dati ir deaktivizēti"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Piemēram, pieteikšanās lapa, iespējams, nepieder norādītajai organizācijai."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Tomēr turpināt, izmantojot pārlūkprogrammu"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Veiktspējas uzlabojums"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Mobilo sakaru operatora piedāvātās 5G iespējas"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Apmeklējiet operatora %s vietni, lai skatītu pieejamās iespējas lietotnē"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Vēlāk"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Pārvaldīt"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Iegādājieties veiktspējas uzlabojumu."</string>
diff --git a/packages/CarrierDefaultApp/res/values-mk/strings.xml b/packages/CarrierDefaultApp/res/values-mk/strings.xml
index 4efecb0..4965d56 100644
--- a/packages/CarrierDefaultApp/res/values-mk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mk/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Комуникации со давателот на услугата"</string>
<string name="android_system_label" msgid="2797790869522345065">"Мобилен оператор"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Мобилниот интернет е искористен"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Мобилниот интернет ви е деактивиран"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"На пример, страницата за најавување може да не припаѓа на прикажаната организација."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Сепак продолжи преку прелистувач"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Засилување на изведбата"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G опции од вашиот давател на услуга"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Посетете го веб-сајтот на %s за да ги видите опциите за искуството со апликацијата"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сега"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управувајте"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Купете засилување на изведбата."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ml/strings.xml b/packages/CarrierDefaultApp/res/values-ml/strings.xml
index f4c19a3..cfeacbe 100644
--- a/packages/CarrierDefaultApp/res/values-ml/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ml/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"സേവനദാതാവ് നടത്തുന്ന ആശയവിനിമയങ്ങൾ"</string>
<string name="android_system_label" msgid="2797790869522345065">"മൊബൈൽ കാരിയർ"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"മൊബൈൽ ഡാറ്റ തീർന്നിരിക്കുന്നു"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"നിങ്ങളുടെ മൊബൈൽ ഡാറ്റ നിർജീവമാക്കി"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ഉദാഹരണത്തിന്, കാണിച്ചിരിക്കുന്ന ഓർഗനൈസേഷന്റേതായിരിക്കില്ല ലോഗിൻ പേജ്."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"എന്തായാലും ബ്രൗസർ വഴി തുടരുക"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"പ്രകടന ബൂസ്റ്റ്"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"നിങ്ങളുടെ സേവനദാതാവിൽ നിന്നുള്ള 5G ഓപ്ഷനുകൾ"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"നിങ്ങളുടെ ആപ്പ് അനുഭവം സംബന്ധിച്ച ഓപ്ഷനുകൾക്ക് %s എന്നതിന്റെ വെബ്സൈറ്റ് സന്ദർശിക്കുക"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ഇപ്പോൾ വേണ്ട"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"മാനേജ് ചെയ്യുക"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"പ്രകടന ബൂസ്റ്റ് വാങ്ങൂ."</string>
diff --git a/packages/CarrierDefaultApp/res/values-mn/strings.xml b/packages/CarrierDefaultApp/res/values-mn/strings.xml
index 2f33eb2..3476ff0 100644
--- a/packages/CarrierDefaultApp/res/values-mn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mn/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Оператор компанийн харилцаа холбоо"</string>
<string name="android_system_label" msgid="2797790869522345065">"Мобайл оператор компани"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Мобайл дата дууссан"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Таны мобайл датаг идэвхгүй болгосон"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Жишээлбэл нэвтрэх хуудас нь харагдаж буй байгууллагынх биш байж болно."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ямар ч тохиолдолд хөтчөөр үргэлжлүүлэх"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Гүйцэтгэлийн идэвхжүүлэлт"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Таны оператор компанийн 5G сонголт"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Аппын хэрэглээнийхээ сонголтыг харахын тулд %s-н вебсайтад зочилно уу"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Одоо биш"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Удирдах"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Гүйцэтгэлийн идэвхжүүлэлтийг худалдаж аваарай."</string>
diff --git a/packages/CarrierDefaultApp/res/values-mr/strings.xml b/packages/CarrierDefaultApp/res/values-mr/strings.xml
index 9414545..4123045 100644
--- a/packages/CarrierDefaultApp/res/values-mr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mr/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"वाहकसह संभाषणे"</string>
<string name="android_system_label" msgid="2797790869522345065">"मोबाइल वाहक"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"मोबाइल डेटा संपला आहे"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"तुमचा मोबाइल डेटा निष्क्रिय केला गेला"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणार्थ, लॉग इन पृष्ठ दर्शवलेल्या संस्थेच्या मालकीचे नसू शकते."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"तरीही ब्राउझरद्वारे सुरू ठेवा"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"परफॉर्मन्स बूस्ट"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"तुमच्या वाहकाकडून 5G पर्याय"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"तुमच्या अॅप अनुभवासाठी पर्याय पाहण्याकरिता %s च्या वेबसाइटला भेट द्या"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"आता नको"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"व्यवस्थापित करा"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"परफॉर्मन्स बूस्ट खरेदी करा."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ms/strings.xml b/packages/CarrierDefaultApp/res/values-ms/strings.xml
index 4fb377e..004d092 100644
--- a/packages/CarrierDefaultApp/res/values-ms/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ms/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Komunikasi Pembawa"</string>
<string name="android_system_label" msgid="2797790869522345065">"Pembawa Mudah Alih"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Data mudah alih telah habis"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Data mudah alih anda telah dinyahaktifkan"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Contohnya, halaman log masuk mungkin bukan milik organisasi yang ditunjukkan."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Teruskan juga melalui penyemak imbas"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Peningkatan prestasi"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Pilihan 5G daripada pembawa anda"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Lawati laman web %s untuk melihat pilihan pengalaman apl anda"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Bukan sekarang"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Urus"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Beli perangsang prestasi."</string>
diff --git a/packages/CarrierDefaultApp/res/values-my/strings.xml b/packages/CarrierDefaultApp/res/values-my/strings.xml
index 002edd8..6e1381f 100644
--- a/packages/CarrierDefaultApp/res/values-my/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-my/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"မိုဘိုင်းဖုန်းကုမ္ပဏီ ဆက်သွယ်မှုများ"</string>
<string name="android_system_label" msgid="2797790869522345065">"မိုဘိုင်း ဝန်ဆောင်မှုပေးသူ"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"မိုဘိုင်းဒေတာ ကုန်သွားပါပြီ"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"သင်၏ မိုဘိုင်း ဒေတာကို ပိတ်ထားပါသည်"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ဥပမာ− ဝင်ရောက်ရန် စာမျက်နှာသည် ပြသထားသည့် အဖွဲ့အစည်းနှင့် သက်ဆိုင်မှုမရှိခြင်း ဖြစ်နိုင်ပါသည်။"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"မည်သို့ပင်ဖြစ်စေ ဘရောက်ဇာမှတစ်ဆင့် ရှေ့ဆက်ရန်"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"စွမ်းဆောင်ရည် မြှင့်တင်အက်ပ်"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"သင်၏ မိုဘိုင်းဖုန်းကုမ္ပဏီထံမှ 5G ရွေးစရာများ"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"သင့်အက်ပ်အသုံးပြုမှုအတွက် ရွေးစရာများကြည့်ရန် %s ၏ ဝဘ်ဆိုက်သို့ ဝင်ကြည့်ပါ"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ယခုမလုပ်ပါ"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"စီမံရန်"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"စွမ်းဆောင်ရည် မြှင့်တင်အက်ပ် ဝယ်ယူရန်။"</string>
diff --git a/packages/CarrierDefaultApp/res/values-ne/strings.xml b/packages/CarrierDefaultApp/res/values-ne/strings.xml
index 169ceff..9bf2fb1 100644
--- a/packages/CarrierDefaultApp/res/values-ne/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ne/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"सेवा प्रदायकसँग गरिएका कुराकानीहरू"</string>
<string name="android_system_label" msgid="2797790869522345065">"मोबाइलको सेवा प्रदायक छनौट गर्नुहोस्"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"मोबाइल डेटा सकियो"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"तपाईंको मोबाइल डेटा निष्क्रिय पारिएको छ"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणका लागि, लग इन पृष्ठ देखाइएको संस्थाको नहुन सक्छ।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"जे भए पनि ब्राउजर मार्फत जारी राख्नुहोस्"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"पर्फर्मेन्स बुस्ट"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"तपाईंको सेवा प्रदायकले उपलब्ध गराएका 5G सम्बन्धी विकल्पहरू"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"एप प्रयोग गर्दा अझ राम्रो सुविधा पाउन %s को वेबसाइटमा गई विकल्पहरू हेर्नुहोस्"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"अहिले होइन"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"व्यवस्थापन गर्नुहोस्"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"पर्फर्मेन्स बुस्ट किन्नुहोस्।"</string>
diff --git a/packages/CarrierDefaultApp/res/values-nl/strings.xml b/packages/CarrierDefaultApp/res/values-nl/strings.xml
index 35ecb3c..b2850c0 100644
--- a/packages/CarrierDefaultApp/res/values-nl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-nl/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Berichten van provider"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobiele provider"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobiele data verbruikt"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Je mobiele data zijn uitgeschakeld"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Zo hoort de weergegeven inlogpagina misschien niet bij de weergegeven organisatie."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Toch doorgaan via browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Prestatieboost"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-opties van je provider"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Ga naar de website van %s om opties voor de app-functionaliteit te zien"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Niet nu"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Beheren"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Koop een prestatieboost."</string>
diff --git a/packages/CarrierDefaultApp/res/values-or/strings.xml b/packages/CarrierDefaultApp/res/values-or/strings.xml
index dc13b65..884af9a 100644
--- a/packages/CarrierDefaultApp/res/values-or/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-or/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"କେରିଅର କମ୍ୟୁନିକେସନ୍ସ"</string>
<string name="android_system_label" msgid="2797790869522345065">"ମୋବାଇଲ୍ କେରିଅର୍"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"ମୋବାଇଲ୍ ଡାଟା ଶେଷ ହୋଇଯାଇଛି"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"ଆପଣଙ୍କ ମୋବାଇଲ୍ ଡାଟା ନିଷ୍କ୍ରୀୟ କରାଯାଇଛି"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ଉଦାହରଣସ୍ୱରୂପ, ଲଗଇନ୍ ପୃଷ୍ଠା ଦେଖାଯାଇଥିବା ସଂସ୍ଥାର ହୋଇନଥାଇପାରେ।"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ବ୍ରାଉଜର୍ ଜରିଆରେ ଯେମିତିବି ହେଉ ଜାରି ରଖନ୍ତୁ"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"ପରଫରମାନ୍ସ ବୁଷ୍ଟ"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"ଆପଣଙ୍କ କେରିଅରରୁ 5G ବିକଳ୍ପଗୁଡ଼ିକ"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ଆପଣଙ୍କ ଆପ ଅନୁଭୂତି ପାଇଁ ବିକଳ୍ପ ଦେଖିବାକୁ %sର ୱେବସାଇଟକୁ ଭିଜିଟ କରନ୍ତୁ"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ବର୍ତ୍ତମାନ ନୁହେଁ"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ଏକ ପରଫରମାନ୍ସ ବୁଷ୍ଟ କିଣନ୍ତୁ।"</string>
diff --git a/packages/CarrierDefaultApp/res/values-pl/strings.xml b/packages/CarrierDefaultApp/res/values-pl/strings.xml
index 3ca001b..3f499a7 100644
--- a/packages/CarrierDefaultApp/res/values-pl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pl/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Informacje od operatora"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operator komórkowy"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Osiągnięto limit komórkowej transmisji danych"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Mobilna transmisja danych została wyłączona"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Na przykład strona logowania może nie należeć do wyświetlanej organizacji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Kontynuuj mimo to w przeglądarce"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Zwiększenie wydajności"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opcje 5G u Twojego operatora"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Opcje dotyczące korzystania z aplikacji znajdziesz na stronie firmy %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nie teraz"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Zarządzaj"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kup wzmocnienie wydajności"</string>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
index cb8329c..cb3bca9 100644
--- a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Comunicações da operadora"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operadora de celular"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Os dados móveis se esgotaram"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Os dados móveis foram desativados"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de performance"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opções 5G da sua operadora"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visite o site de %s para conferir opções da sua experiência no app"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerenciar"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar um aumento de performance."</string>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
index 7e435cf..137a1c6 100644
--- a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Comunicações do operador"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operador móvel"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Dados móveis esgotados"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Os seus dados móveis foram desativados"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de início de sessão pode não pertencer à entidade apresentada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim através do navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento do desempenho"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opções 5G do seu operador"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visite o Website de %s para ver opções para a experiência da sua app"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerir"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Compre um aumento do desempenho."</string>
diff --git a/packages/CarrierDefaultApp/res/values-pt/strings.xml b/packages/CarrierDefaultApp/res/values-pt/strings.xml
index cb8329c..cb3bca9 100644
--- a/packages/CarrierDefaultApp/res/values-pt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Comunicações da operadora"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operadora de celular"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Os dados móveis se esgotaram"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Os dados móveis foram desativados"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Aumento de performance"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opções 5G da sua operadora"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Visite o site de %s para conferir opções da sua experiência no app"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Agora não"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gerenciar"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Comprar um aumento de performance."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ro/strings.xml b/packages/CarrierDefaultApp/res/values-ro/strings.xml
index 042d9ec..78b910e 100644
--- a/packages/CarrierDefaultApp/res/values-ro/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ro/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Comunicări de la operator"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operator de telefonie mobilă"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Datele mobile au expirat"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Datele mobile au fost dezactivate"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"De exemplu, este posibil ca pagina de conectare să nu aparțină organizației afișate."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Continuă oricum prin browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Boost de performanță"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opțiuni 5G de la operator"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Accesează site-ul %s ca să vezi opțiunile pentru experiența ta cu aplicațiile"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Nu acum"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Gestionează"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Achiziționează un boost de performanță."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ru/strings.xml b/packages/CarrierDefaultApp/res/values-ru/strings.xml
index 0c25796..936a6fa 100644
--- a/packages/CarrierDefaultApp/res/values-ru/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ru/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Оператор связи"</string>
<string name="android_system_label" msgid="2797790869522345065">"Оператор мобильной связи"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Мобильный трафик израсходован"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Мобильный Интернет отключен"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Например, страница входа в аккаунт может быть фиктивной."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Продолжить в браузере"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Повышение производительности"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Сеть 5G от оператора связи"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Посетите сайт оператора (%s), чтобы узнать, как улучшить производительность приложения."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сейчас"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Настроить"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Повысьте производительность сети за плату."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sk/strings.xml b/packages/CarrierDefaultApp/res/values-sk/strings.xml
index e14e087..77951cf 100644
--- a/packages/CarrierDefaultApp/res/values-sk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sk/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Komunikácie s operátorom"</string>
<string name="android_system_label" msgid="2797790869522345065">"Poskytovateľ mobilných služieb"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobilné dáta sa minuli"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Vaše mobilné dáta boli deaktivované"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Napríklad prihlasovacia stránka nemusí patriť uvedenej organizácii."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Pokračovať pomocou prehliadača"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Zvýšenie výkonu"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Možnosti siete 5G od vášho operátora"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Ak chcete zistiť, aké sú možnosti prostredia v aplikácii, prejdite na web %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Teraz nie"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Spravovať"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kúpte si zvýšenie výkonu."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sl/strings.xml b/packages/CarrierDefaultApp/res/values-sl/strings.xml
index 21cb944..bee2217 100644
--- a/packages/CarrierDefaultApp/res/values-sl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sl/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobilni operater"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Porabili ste vse mobilne podatke"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Prenos podatkov v mobilnih omrežjih je deaktiviran"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Stran za prijavo na primer morda ne pripada prikazani organizaciji."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vseeno nadaljuj v brskalniku"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Ojačevalnik zmogljivosti"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Operaterjeve možnosti 5G"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Obiščite spletno mesto %s, da si ogledate možnosti izkušnje aplikacije."</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Ne zdaj"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Upravljanje"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Kupite ojačevalnik zmogljivosti."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sq/strings.xml b/packages/CarrierDefaultApp/res/values-sq/strings.xml
index 9d501d9..238921a 100644
--- a/packages/CarrierDefaultApp/res/values-sq/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sq/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Komunikimet e operatorit celular"</string>
<string name="android_system_label" msgid="2797790869522345065">"Operatori celular"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Të dhënat celulare kanë përfunduar"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Të dhënat celulare janë çaktivizuar"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"për shembull, faqja e identifikimit mund të mos i përkasë organizatës së shfaqur."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vazhdo gjithsesi nëpërmjet shfletuesit"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Përforcimi i performancës"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Opsionet 5G nga operatori yt celular"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Vizito sajtin e uebit të %s për të parë opsione për përvojën tënde me aplikacionin"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Jo tani"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Menaxho"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Bli një paketë përforcimi të performancës."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sr/strings.xml b/packages/CarrierDefaultApp/res/values-sr/strings.xml
index 257d53b..c99431b 100644
--- a/packages/CarrierDefaultApp/res/values-sr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sr/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Обавештења мобилног оператера"</string>
<string name="android_system_label" msgid="2797790869522345065">"Мобилни оператер"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Мобилни подаци су потрошени"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Мобилни подаци су деактивирани"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"На пример, страница за пријављивање можда не припада приказаној организацији."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Ипак настави преко прегледача"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Побољшање учинка"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G опције мобилног оператера"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Опције за доживљај апликације потражите на веб-сајту мобилног оператера %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Не сада"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Управљај"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Купите побољшање учинка."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sv/strings.xml b/packages/CarrierDefaultApp/res/values-sv/strings.xml
index 1886ed9..d2e8d93 100644
--- a/packages/CarrierDefaultApp/res/values-sv/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sv/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Carrier Communications"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobiloperatör"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Slut på mobildata"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Din mobildata har inaktiverats"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Det kan t.ex. hända att inloggningssidan inte tillhör den organisation som visas."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Fortsätt ändå via webbläsaren"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Prestandahöjning"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"5G-alternativ från operatören"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Se alternativ för appupplevelsen på webbplatsen för %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Inte nu"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Hantera"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Köp en prestandahöjning."</string>
diff --git a/packages/CarrierDefaultApp/res/values-sw/strings.xml b/packages/CarrierDefaultApp/res/values-sw/strings.xml
index fc3450f..5dc7921 100644
--- a/packages/CarrierDefaultApp/res/values-sw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sw/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Mawasiliano ya Mtoa Huduma"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mtoa Huduma za Simu"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Data ya mtandao wa simu imekwisha"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Data yako ya mtandao wa simu imezimwa"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Kwa mfano, ukurasa wa kuingia katika akaunti unaweza usiwe unamilikiwa na shirika lililoonyeshwa."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Endelea hata hivyo kupitia kivinjari"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Kuongeza utendaji"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Chaguo za 5G kutoka kwa mtoa huduma wako"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Tembelea tovuti ya %s ili uone chaguo za hali ya matumizi ya programu yako"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Si sasa"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Dhibiti"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Nunua programu ya kuongeza utendaji."</string>
diff --git a/packages/CarrierDefaultApp/res/values-te/strings.xml b/packages/CarrierDefaultApp/res/values-te/strings.xml
index 944ee75..5f86828 100644
--- a/packages/CarrierDefaultApp/res/values-te/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-te/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"క్యారియర్ కమ్యూనికేషన్లు"</string>
<string name="android_system_label" msgid="2797790869522345065">"మొబైల్ క్యారియర్"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"మొబైల్ డేటాను పూర్తిగా ఉపయోగించారు"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"మీ మొబైల్ డేటా నిష్క్రియం చేయబడింది"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ఉదాహరణకు, లాగిన్ పేజీ చూపిన సంస్థకు చెందినది కాకపోవచ్చు."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ఏదేమైనా బ్రౌజర్ ద్వారా కొనసాగించండి"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"పనితీరు బూస్ట్"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"మీ క్యారియర్ నుండి 5G ఆప్షన్లు"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"మీ యాప్ అనుభవం కోసం ఆప్షన్లను చూడటానికి %s వెబ్సైట్కు వెళ్లండి"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ఇప్పుడు కాదు"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"మేనేజ్ చేయండి"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"పనితీరు బూస్ట్ను కొనుగోలు చేయండి."</string>
diff --git a/packages/CarrierDefaultApp/res/values-th/strings.xml b/packages/CarrierDefaultApp/res/values-th/strings.xml
index e13ce44..586ffd5 100644
--- a/packages/CarrierDefaultApp/res/values-th/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-th/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"การสื่อสารจากผู้ให้บริการ"</string>
<string name="android_system_label" msgid="2797790869522345065">"ผู้ให้บริการเครือข่ายมือถือ"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"เน็ตมือถือหมดแล้ว"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"อินเทอร์เน็ตมือถือของคุณถูกปิดใช้งานแล้ว"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"ตัวอย่างเช่น หน้าเข้าสู่ระบบอาจไม่ใช่ขององค์กรที่แสดงไว้"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"ดำเนินการต่อผ่านเบราว์เซอร์"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"การเพิ่มประสิทธิภาพ"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"ตัวเลือก 5G จากผู้ให้บริการ"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"ดูตัวเลือกต่างๆ สำหรับประสบการณ์การใช้งานแอปได้ที่เว็บไซต์ของ %s"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ไว้ทีหลัง"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"จัดการ"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"ซื้อการเพิ่มประสิทธิภาพ"</string>
diff --git a/packages/CarrierDefaultApp/res/values-tl/strings.xml b/packages/CarrierDefaultApp/res/values-tl/strings.xml
index bdb09ac..a311a25 100644
--- a/packages/CarrierDefaultApp/res/values-tl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-tl/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Mga Pakikipag-ugnayan sa Carrier"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobile Carrier"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Naubos na ang mobile data"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Na-deactivate na ang iyong mobile data"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Halimbawa, maaaring hindi pag-aari ng ipinapakitang organisasyon ang page ng login."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Magpatuloy pa rin sa pamamagitan ng browser"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Pag-boost ng performance"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Mga opsyon sa 5G mula sa carrier mo"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Pumunta sa website ng %s para tingnan ang mga opsyon para sa iyong experience sa app"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Huwag muna"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Pamahalaan"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Bumili ng pang-boost ng performance."</string>
diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml
index ef2677f..0c7cdc5 100644
--- a/packages/CarrierDefaultApp/res/values-ur/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"کیریئر سے متعلق مواصلات"</string>
<string name="android_system_label" msgid="2797790869522345065">"موبائل کیریئر"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"موبائل ڈیٹا ختم ہو چکا ہے"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"آپ کا موبائل ڈیٹا غیر فعال کر دیا گیا ہے"</string>
@@ -16,8 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"مثال کے طور پر ہو سکتا ہے کہ لاگ ان صفحہ دکھائی گئی تنظیم سے تعلق نہ رکھتا ہو۔"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"پرفارمینس بوسٹ"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"آپ کے کیریئر سے 5G کے اختیارات"</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
<skip />
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"ابھی نہیں"</string>
diff --git a/packages/CarrierDefaultApp/res/values-uz/strings.xml b/packages/CarrierDefaultApp/res/values-uz/strings.xml
index dd48975..0f25e7e 100644
--- a/packages/CarrierDefaultApp/res/values-uz/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-uz/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Operator aloqasi"</string>
<string name="android_system_label" msgid="2797790869522345065">"Mobil aloqa operatori"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Mobil internet tugab qoldi"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Mobil internet o‘chirildi"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Masalan, tizimga kirish sahifasi ko‘rsatilgan tashkilotga tegishli bo‘lmasligi mumkin."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Brauzerda davom ettirish"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Unumdorlikni kuchaytirish"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Operatordan 5G aloqa parametrlari"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Ilovadan foydalanish usullarini koʻrish uchun %s saytini oching"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Hozir emas"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Boshqarish"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Unumdorlikni kuchaytirish xizmatini xarid qiling."</string>
diff --git a/packages/CarrierDefaultApp/res/values-vi/strings.xml b/packages/CarrierDefaultApp/res/values-vi/strings.xml
index b01f951..d99aa22 100644
--- a/packages/CarrierDefaultApp/res/values-vi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-vi/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Nhà cung cấp dịch vụ truyền thông"</string>
<string name="android_system_label" msgid="2797790869522345065">"Nhà cung cấp dịch vụ di động"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Dữ liệu di động đã hết"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Dữ liệu di động của bạn đã bị hủy kích hoạt"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Ví dụ: trang đăng nhập có thể không thuộc về tổ chức được hiển thị."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Vẫn tiếp tục qua trình duyệt"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"Tăng hiệu suất"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Tuỳ chọn 5G từ nhà mạng của bạn"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Truy cập trang web của %s để xem các lựa chọn cho trải nghiệm trên ứng dụng"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Để sau"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Quản lý"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Mua gói tăng hiệu suất."</string>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
index e06cddb..b05835d 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"运营商通信"</string>
<string name="android_system_label" msgid="2797790869522345065">"移动运营商"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"移动数据流量已用尽"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"您的移动数据网络已停用"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"例如,登录页面可能并不属于页面上显示的单位。"</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"仍然通过浏览器继续操作"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"性能提升方案"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"您的运营商提供的 5G 选项"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"访问%s的网站可查看您的应用体验选项"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"以后再说"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"管理"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"购买一份性能提升方案。"</string>
diff --git a/packages/CarrierDefaultApp/res/values-zu/strings.xml b/packages/CarrierDefaultApp/res/values-zu/strings.xml
index dc09c9d..e624a19 100644
--- a/packages/CarrierDefaultApp/res/values-zu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zu/strings.xml
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (2809080280462257271) -->
- <skip />
+ <string name="app_name" msgid="2809080280462257271">"Inkampani Yezokuxhumana"</string>
<string name="android_system_label" msgid="2797790869522345065">"Inkampini yenethiwekhi yeselula"</string>
<string name="portal_notification_id" msgid="5155057562457079297">"Idatha yeselula iphelile"</string>
<string name="no_data_notification_id" msgid="668400731803969521">"Idatha yakho yeselula yenziwe yangasebenzi"</string>
@@ -16,10 +15,8 @@
<string name="ssl_error_example" msgid="6188711843183058764">"Isibonelo, ikhasi lokungena ngemvume kungenzeka lingelenhlangano ebonisiwe."</string>
<string name="ssl_error_continue" msgid="1138548463994095584">"Qhubeka noma kunjalo ngesiphequluli"</string>
<string name="performance_boost_notification_channel" msgid="3475440855635538592">"I-boost yokusebenza"</string>
- <!-- no translation found for performance_boost_notification_title (3126203390685781861) -->
- <skip />
- <!-- no translation found for performance_boost_notification_detail (216569851036236346) -->
- <skip />
+ <string name="performance_boost_notification_title" msgid="3126203390685781861">"Okukhethwa kukho kwe-5G okuvela kunkampani yakho yenethiwekhi"</string>
+ <string name="performance_boost_notification_detail" msgid="216569851036236346">"Vakashela iwebhusayithi ye-%s ukuze ubone okukhethwa kukho kolwazi lwakho lwe-app"</string>
<string name="performance_boost_notification_button_not_now" msgid="6459755324243683785">"Hhayi manje"</string>
<string name="performance_boost_notification_button_manage" msgid="4976836444046497973">"Phatha"</string>
<string name="slice_purchase_app_label" msgid="7170191659233241166">"Thenga i-boost yokusebenza."</string>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index bd0b4cc..b3d3b6d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -232,6 +232,13 @@
))
}
is PublicKeyCredentialEntry -> {
+ val passkeyUsername = credentialEntry.username.toString()
+ val passkeyDisplayName = credentialEntry.displayName?.toString() ?: ""
+ val (username, displayName) = userAndDisplayNameForPasskey(
+ passkeyUsername = passkeyUsername,
+ passkeyDisplayName = passkeyDisplayName,
+ )
+
result.add(CredentialEntryInfo(
providerId = providerId,
providerDisplayName = providerLabel,
@@ -241,8 +248,8 @@
fillInIntent = it.frameworkExtrasIntent,
credentialType = CredentialType.PASSKEY,
credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
- userName = credentialEntry.username.toString(),
- displayName = credentialEntry.displayName?.toString(),
+ userName = username,
+ displayName = displayName,
icon = credentialEntry.icon.loadDrawable(context),
shouldTintIcon = credentialEntry.isDefaultIcon,
lastUsedTimeMillis = credentialEntry.lastUsedTime,
@@ -646,16 +653,20 @@
preferImmediatelyAvailableCredentials: Boolean,
): RequestDisplayInfo? {
val json = JSONObject(requestJson)
- var name = ""
- var displayName = ""
+ var passkeyUsername = ""
+ var passkeyDisplayName = ""
if (json.has("user")) {
val user: JSONObject = json.getJSONObject("user")
- name = user.getString("name")
- displayName = user.getString("displayName")
+ passkeyUsername = user.getString("name")
+ passkeyDisplayName = user.getString("displayName")
}
+ val (username, displayname) = userAndDisplayNameForPasskey(
+ passkeyUsername = passkeyUsername,
+ passkeyDisplayName = passkeyDisplayName,
+ )
return RequestDisplayInfo(
- name,
- displayName,
+ username,
+ displayname,
CredentialType.PASSKEY,
appLabel,
context.getDrawable(R.drawable.ic_passkey_24) ?: return null,
@@ -664,3 +675,30 @@
}
}
}
+
+/**
+ * Returns the actual username and display name for the UI display purpose for the passkey use case.
+ *
+ * Passkey has some special requirements:
+ * 1) display-name on top (turned into UI username) if one is available, username on second line.
+ * 2) username on top if display-name is not available.
+ * 3) don't show username on second line if username == display-name
+ */
+private fun userAndDisplayNameForPasskey(
+ passkeyUsername: String,
+ passkeyDisplayName: String,
+): Pair<String, String> {
+ if (!TextUtils.isEmpty(passkeyUsername) && !TextUtils.isEmpty(passkeyDisplayName)) {
+ if (passkeyUsername == passkeyDisplayName) {
+ return Pair(passkeyUsername, "")
+ } else {
+ return Pair(passkeyDisplayName, passkeyUsername)
+ }
+ } else if (!TextUtils.isEmpty(passkeyUsername)) {
+ return Pair(passkeyUsername, passkeyDisplayName)
+ } else if (!TextUtils.isEmpty(passkeyDisplayName)) {
+ return Pair(passkeyDisplayName, passkeyUsername)
+ } else {
+ return Pair(passkeyDisplayName, passkeyUsername)
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
index bba08f4..7a720b1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
@@ -43,14 +43,18 @@
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import com.android.credentialmanager.R
import com.android.credentialmanager.ui.theme.EntryShape
@@ -336,7 +340,7 @@
contentDescription = stringResource(
R.string.accessibility_back_arrow_button
),
- modifier = Modifier.size(24.dp),
+ modifier = Modifier.size(24.dp).autoMirrored(),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
@@ -345,4 +349,11 @@
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding)
)
+}
+
+private fun Modifier.autoMirrored() = composed {
+ when (LocalLayoutDirection.current) {
+ LayoutDirection.Rtl -> graphicsLayer(scaleX = -1f)
+ else -> this
+ }
}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 5632458..c27ac94 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -59,6 +59,8 @@
import com.android.credentialmanager.common.ui.SnackbarActionText
import com.android.credentialmanager.common.ui.HeadlineText
import com.android.credentialmanager.common.ui.CredentialListSectionHeader
+import com.android.credentialmanager.common.ui.HeadlineIcon
+import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
import com.android.credentialmanager.common.ui.Snackbar
import com.android.credentialmanager.common.ui.setTransparentSystemBarsColor
import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor
@@ -167,22 +169,42 @@
providerDisplayInfo.sortedUserNameToCredentialEntryList
val authenticationEntryList = providerDisplayInfo.authenticationEntryList
SheetContainerCard {
+ // When only one provider (not counting the remote-only provider) exists, display that
+ // provider's icon + name up top.
+ if (providerInfoList.size <= 2) { // It's only possible to be the single provider case
+ // if we are started with no more than 2 providers.
+ val nonRemoteProviderList = providerInfoList.filter(
+ { it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() }
+ )
+ if (nonRemoteProviderList.size == 1) {
+ val providerInfo = nonRemoteProviderList.firstOrNull() // First should always work
+ // but just to be safe.
+ if (providerInfo != null) {
+ item {
+ HeadlineIcon(
+ bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
+ tint = Color.Unspecified,
+ )
+ }
+ item { Divider(thickness = 4.dp, color = Color.Transparent) }
+ item { LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName) }
+ item { Divider(thickness = 16.dp, color = Color.Transparent) }
+ }
+ }
+ }
+
+ val hasSingleEntry = (sortedUserNameToCredentialEntryList.size == 1 &&
+ authenticationEntryList.isEmpty()) || (sortedUserNameToCredentialEntryList.isEmpty() &&
+ authenticationEntryList.size == 1)
item {
HeadlineText(
text = stringResource(
- if (sortedUserNameToCredentialEntryList
- .size == 1 && authenticationEntryList.isEmpty()
- ) {
- if (sortedUserNameToCredentialEntryList.first()
- .sortedCredentialEntryList.first().credentialType
+ if (hasSingleEntry) {
+ if (sortedUserNameToCredentialEntryList.firstOrNull()
+ ?.sortedCredentialEntryList?.first()?.credentialType
== CredentialType.PASSKEY
) R.string.get_dialog_title_use_passkey_for
else R.string.get_dialog_title_use_sign_in_for
- } else if (
- sortedUserNameToCredentialEntryList
- .isEmpty() && authenticationEntryList.size == 1
- ) {
- R.string.get_dialog_title_use_sign_in_for
} else R.string.get_dialog_title_choose_sign_in_for,
requestDisplayInfo.appName
),
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 5562684..2c4b478 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -422,7 +422,7 @@
Log.e(TAG, "Failed to disable DynamicSystem.");
// Dismiss status bar and show a toast.
- sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ closeSystemDialogs();
Toast.makeText(this,
getString(R.string.toast_failed_to_disable_dynsystem),
Toast.LENGTH_LONG).show();
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
index b67eb3d..ba8c03d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
@@ -19,6 +19,8 @@
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AirplanemodeActive
@@ -140,6 +142,7 @@
paddingVertical = paddingVertical,
icon = icon,
) {
+ Spacer(Modifier.width(SettingsDimension.itemPaddingEnd))
SettingsSwitch(
checked = checked,
changeable = changeable,
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 241d6d5..08c2f7b 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -245,12 +245,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi-tilkoblingskode"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Tilkoblingen mislyktes"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sørg for at enheten er koblet til samme nettverk."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via Wifi ved å skanne en QR-kode"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via wifi ved å skanne en QR-kode"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Kobler til enheten …"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Kunne ikke koble til enheten. Enten var QR-koden feil, eller enheten er ikke koblet til samme nettverk."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skann QR-koden"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via Wifi ved å skanne en QR-kode"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via wifi ved å skanne en QR-kode"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et Wifi-nettverk"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, feilsøking, utvikler"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Snarvei til feilrapport"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index b6a3a62..0e3afae 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -213,7 +213,7 @@
<item msgid="6946761421234586000">"Asilimia 400"</item>
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Chagua wasifu"</string>
- <string name="category_personal" msgid="6236798763159385225">"Ya Binafsi"</string>
+ <string name="category_personal" msgid="6236798763159385225">"Binafsi"</string>
<string name="category_work" msgid="4014193632325996115">"Ya Kazini"</string>
<string name="development_settings_title" msgid="140296922921597393">"Chaguo za wasanidi"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Washa chaguo za wasanidi programu"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a3d632c..04168ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -940,6 +940,7 @@
+ getName()
+ ", groupId="
+ mGroupId
+ + ", member= " + mMemberDevices
+ ")";
}
@@ -1494,33 +1495,6 @@
}
/**
- * In order to show the preference for the whole group, we always set the main device as the
- * first connected device in the coordinated set, and then switch the content of the main
- * device and member devices.
- *
- * @param newMainDevice the new Main device which is from the previous main device's member
- * list.
- */
- public void switchMemberDeviceContent(CachedBluetoothDevice newMainDevice) {
- // Backup from main device
- final BluetoothDevice tmpDevice = mDevice;
- final short tmpRssi = mRssi;
- final boolean tmpJustDiscovered = mJustDiscovered;
- // Set main device from sub device
- release();
- mDevice = newMainDevice.mDevice;
- mRssi = newMainDevice.mRssi;
- mJustDiscovered = newMainDevice.mJustDiscovered;
-
- // Set sub device from backup
- newMainDevice.release();
- newMainDevice.mDevice = tmpDevice;
- newMainDevice.mRssi = tmpRssi;
- newMainDevice.mJustDiscovered = tmpJustDiscovered;
- fetchActiveDevices();
- }
-
- /**
* Get cached bluetooth icon with description
*/
public Pair<Drawable, String> getDrawableWithDescription() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 7b4c862..d191b1e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -464,6 +464,59 @@
return !(mOngoingSetMemberPair == null) && mOngoingSetMemberPair.equals(device);
}
+ /**
+ * In order to show the preference for the whole group, we always set the main device as the
+ * first connected device in the coordinated set, and then switch the relationship of the main
+ * device and member devices.
+ *
+ * @param newMainDevice the new Main device which is from the previous main device's member
+ * list.
+ */
+ public void switchRelationshipFromMemberToMain(CachedBluetoothDevice newMainDevice) {
+ if (newMainDevice == null) {
+ log("switchRelationshipFromMemberToMain: input is null");
+ return;
+ }
+ log("switchRelationshipFromMemberToMain: CachedBluetoothDevice list: " + mCachedDevices);
+
+ final CachedBluetoothDevice finalNewMainDevice = newMainDevice;
+ int newMainGroupId = newMainDevice.getGroupId();
+ CachedBluetoothDevice oldMainDevice = mCachedDevices.stream()
+ .filter(cachedDevice -> !cachedDevice.equals(finalNewMainDevice)
+ && cachedDevice.getGroupId() == newMainGroupId).findFirst().orElse(null);
+ boolean hasMainDevice = oldMainDevice != null;
+ Set<CachedBluetoothDevice> memberSet =
+ hasMainDevice ? oldMainDevice.getMemberDevice() : null;
+ boolean isMemberDevice = memberSet != null && memberSet.contains(newMainDevice);
+ if (!hasMainDevice || !isMemberDevice) {
+ log("switchRelationshipFromMemberToMain: "
+ + newMainDevice.getDevice().getAnonymizedAddress()
+ + " is not the member device.");
+ return;
+ }
+
+ mCachedDevices.remove(oldMainDevice);
+ // When both LE Audio devices are disconnected, receiving member device
+ // connection. To switch content and dispatch to notify UI change
+ mBtManager.getEventManager().dispatchDeviceRemoved(oldMainDevice);
+
+ for (CachedBluetoothDevice memberDeviceItem : memberSet) {
+ if (memberDeviceItem.equals(newMainDevice)) {
+ continue;
+ }
+ newMainDevice.addMemberDevice(memberDeviceItem);
+ }
+ memberSet.clear();
+ newMainDevice.addMemberDevice(oldMainDevice);
+
+ mCachedDevices.add(newMainDevice);
+ // It is necessary to do remove and add for updating the mapping on
+ // preference and device
+ mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice);
+ log("switchRelationshipFromMemberToMain: After change, CachedBluetoothDevice list: "
+ + mCachedDevices);
+ }
+
private void log(String msg) {
if (DEBUG) {
Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 20a6cd8..814c395 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -238,14 +238,10 @@
mainDevice.refresh();
return true;
} else {
- // When both LE Audio devices are disconnected, receiving member device
- // connection. To switch content and dispatch to notify UI change
- mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
- mainDevice.switchMemberDeviceContent(cachedDevice);
- mainDevice.refresh();
- // It is necessary to do remove and add for updating the mapping on
- // preference and device
- mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+ final CachedBluetoothDeviceManager deviceManager =
+ mBtManager.getCachedDeviceManager();
+ deviceManager.switchRelationshipFromMemberToMain(cachedDevice);
+ cachedDevice.refresh();
return true;
}
}
@@ -266,14 +262,10 @@
for (CachedBluetoothDevice device: memberSet) {
if (device.isConnected()) {
log("set device: " + device + " as the main device");
- // Main device is disconnected and sub device is connected
- // To copy data from sub device to main device
- mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
- cachedDevice.switchMemberDeviceContent(device);
- cachedDevice.refresh();
- // It is necessary to do remove and add for updating the mapping on
- // preference and device
- mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
+ final CachedBluetoothDeviceManager deviceManager =
+ mBtManager.getCachedDeviceManager();
+ deviceManager.switchRelationshipFromMemberToMain(device);
+ device.refresh();
return true;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/OWNERS b/packages/SettingsLib/src/com/android/settingslib/mobile/OWNERS
index ab9b5dc..c01528fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/OWNERS
@@ -1,4 +1,7 @@
# Default reviewers for this and subdirectories.
-bonianchen@google.com
+songferngwang@google.com
+zoeychen@google.com
# Emergency approvers in case the above are not available
+changbetty@google.com
+tomhsu@google.com
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/OWNERS b/packages/SettingsLib/src/com/android/settingslib/net/OWNERS
index ab9b5dc..c01528fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/net/OWNERS
@@ -1,4 +1,7 @@
# Default reviewers for this and subdirectories.
-bonianchen@google.com
+songferngwang@google.com
+zoeychen@google.com
# Emergency approvers in case the above are not available
+changbetty@google.com
+tomhsu@google.com
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 4b3820e..1791dce 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -604,4 +604,87 @@
verify(mDevice2).setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
verify(mDevice2).createBond(BluetoothDevice.TRANSPORT_LE);
}
+
+ @Test
+ public void switchRelationshipFromMemberToMain_switchesMainDevice_switchesSuccessful() {
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1);
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2);
+ doReturn(CAP_GROUP2).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3);
+ CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
+ CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isFalse();
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isTrue();
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isFalse();
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue();
+
+ mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice2);
+
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isTrue();
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isFalse();
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isFalse();
+ assertThat(cachedDevice2.getMemberDevice().contains(cachedDevice1)).isTrue();
+ }
+
+ @Test
+ public void switchRelationshipFromMemberToMain_moreMembersCase_switchesSuccessful() {
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1);
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2);
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3);
+ CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
+ CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue();
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue();
+
+ mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice2);
+
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isTrue();
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isFalse();
+ assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isTrue();
+ assertThat(cachedDevice2.getMemberDevice().contains(cachedDevice1)).isTrue();
+ assertThat(cachedDevice2.getMemberDevice().contains(cachedDevice3)).isTrue();
+ }
+
+ @Test
+ public void switchRelationshipFromMemberToMain_inputDeviceIsMainDevice_doesNotChangelist() {
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1);
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2);
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3);
+ CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
+ CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
+ Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue();
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue();
+
+ mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice1);
+
+ devices = mCachedDeviceManager.getCachedDevicesCopy();
+ assertThat(devices).contains(cachedDevice1);
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isTrue();
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue();
+ }
+
+ @Test
+ public void switchRelationshipFromMemberToMain_inputDeviceNotInMemberList_doesNotChangelist() {
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1);
+ CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2);
+ doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3);
+ CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
+ cachedDevice1.getMemberDevice().remove(cachedDevice2);
+ CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
+ Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
+
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isFalse();
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue();
+
+ mCachedDeviceManager.switchRelationshipFromMemberToMain(cachedDevice2);
+
+ devices = mCachedDeviceManager.getCachedDevicesCopy();
+ assertThat(devices).contains(cachedDevice1);
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isFalse();
+ assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 1c179f8..ff1af92 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -1138,25 +1138,6 @@
}
@Test
- public void switchMemberDeviceContent_switchMainDevice_switchesSuccessful() {
- mCachedDevice.mRssi = RSSI_1;
- mCachedDevice.mJustDiscovered = JUSTDISCOVERED_1;
- mSubCachedDevice.mRssi = RSSI_2;
- mSubCachedDevice.mJustDiscovered = JUSTDISCOVERED_2;
- mCachedDevice.addMemberDevice(mSubCachedDevice);
-
- mCachedDevice.switchMemberDeviceContent(mSubCachedDevice);
-
- assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2);
- assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2);
- assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice);
- assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1);
- assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
- assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice);
- assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
- }
-
- @Test
public void isConnectedHearingAidDevice_isConnectedAshaHearingAidDevice_returnTrue() {
when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index e0e3720..a9d1464 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -137,6 +137,7 @@
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
+ Settings.Global.AUTO_TIME_ZONE_EXPLICIT,
Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 6f7d20a..067efe9 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1697,7 +1697,7 @@
}
private void collapseNotificationBar() {
- sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ closeSystemDialogs();
}
private static Looper newLooper(String name) {
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-night/a11ymenu_intro.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-night/a11ymenu_intro.xml
index b2a0b32..c2fe06a4 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-night/a11ymenu_intro.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-night/a11ymenu_intro.xml
@@ -7,84 +7,67 @@
android:fillColor="#FF000000"
android:pathData="M383.9,300H28.1c-15.5,0 -28.1,-12.6 -28.1,-28.1V28.1C0,12.6 12.6,0 28.1,0H383.9c15.5,0 28.1,12.6 28.1,28.1v243.8c0,15.5 -12.6,28.1 -28.1,28.1Z"/>
<path
- android:pathData="M106.4,0h195.3c2,0 3.6,0.2 3.6,0.4V31.2c0,0.2 -1.6,0.4 -3.6,0.4H106.4c-2,0 -3.6,-0.2 -3.6,-0.4V0.4c0,-0.2 1.6,-0.4 3.6,-0.4Z"
- android:fillColor="#3b4043"/>
- <path
- android:pathData="M303.7,238.9H104.5v1h98.4v29.5h1v-29.5h99.8v-1Z"
- android:fillColor="#3b4043"/>
- <path
- android:pathData="M153.7,258.3l0.7,-0.7 -2.7,-2.7h5.9v-1h-5.9l2.7,-2.7 -0.7,-0.7 -3.9,3.9 3.9,3.9Z"
- android:fillColor="#3b4043"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M253.5,250.4l-0.7,0.7 2.7,2.7h-5.9v1h5.9l-2.7,2.7 0.7,0.7 3.9,-3.9 -3.9,-3.9Z"
- android:fillColor="#7f868c"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M119.3,273h169.8c10.2,0 18.5,-8.3 18.5,-18.5V73.7c2,0 3.7,-1.7 3.7,-3.7V33.1c0,-2 -1.7,-3.7 -3.7,-3.7V0h-3.7V254.5c0,8.1 -6.6,14.8 -14.8,14.8H119.3c-8.1,0 -14.8,-6.6 -14.8,-14.8V0h-3.7V254.5c0,10.2 8.3,18.5 18.5,18.5Z"
- android:fillColor="#80868b"/>
- <path
- android:pathData="M141.86,52.23h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M119.3,39.17h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#2197f3"/>
<path
- android:fillColor="#FF000000"
- android:pathData="M141.86,81.15l-2.93,-2.93h-4.39c-0.39,0 -0.73,-0.15 -1.02,-0.44 -0.29,-0.29 -0.44,-0.63 -0.44,-1.02v-14.63c0,-0.39 0.15,-0.73 0.44,-1.02 0.29,-0.29 0.63,-0.44 1.02,-0.44h14.63c0.39,0 0.73,0.15 1.02,0.44 0.29,0.29 0.44,0.63 0.44,1.02v14.63c0,0.39 -0.15,0.73 -0.44,1.02 -0.29,0.29 -0.63,0.44 -1.02,0.44h-4.39l-2.93,2.93ZM141.88,74l1.37,-3.12 3.12,-1.37 -3.12,-1.37 -1.37,-3.12 -1.39,3.12 -3.1,1.37 3.1,1.37 1.39,3.12Z"/>
- <path
- android:pathData="M270.14,52.23h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M292.7,39.17h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#dbdce0"/>
<path
android:fillColor="#FF000000"
- android:pathData="M269.25,62.01h1.77v8.74h-1.77v-8.74ZM274.01,65.22l1.22,-1.22c1.66,1.44 2.76,3.54 2.76,5.97 0,4.31 -3.54,7.85 -7.85,7.85s-7.85,-3.54 -7.85,-7.85c0,-2.43 1.11,-4.53 2.76,-5.97l1.22,1.22c-1.33,1.11 -2.21,2.88 -2.21,4.76 0,3.43 2.76,6.19 6.19,6.19 3.43,0 6.19,-2.76 6.19,-6.19 -0.11,-1.99 -1.11,-3.65 -2.43,-4.76Z"
+ android:pathData="M291.5,52.4h2.39v11.81h-2.39v-11.81ZM297.93,56.74l1.64,-1.64c2.24,1.94 3.74,4.78 3.74,8.07 0,5.83 -4.78,10.61 -10.61,10.61s-10.61,-4.78 -10.61,-10.61c0,-3.29 1.49,-6.13 3.74,-8.07l1.64,1.64c-1.79,1.49 -2.99,3.89 -2.99,6.43 0,4.63 3.74,8.37 8.37,8.37 4.63,0 8.37,-3.74 8.37,-8.37 -0.15,-2.69 -1.49,-4.93 -3.29,-6.43Z"
android:fillType="evenOdd"/>
<path
- android:pathData="M207.03,52.23h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M207.39,39.17h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#d9affd"/>
<path
android:fillColor="#FF000000"
- android:pathData="M207.03,62.6c-0.44,0 -0.81,-0.16 -1.13,-0.47 -0.31,-0.31 -0.47,-0.69 -0.47,-1.13s0.16,-0.81 0.47,-1.13c0.31,-0.31 0.69,-0.47 1.13,-0.47s0.81,0.16 1.13,0.47c0.31,0.31 0.47,0.69 0.47,1.13s-0.16,0.81 -0.47,1.13 -0.69,0.47 -1.13,0.47ZM204.75,76.06v-10.83c-0.92,-0.07 -1.85,-0.18 -2.78,-0.32 -0.94,-0.14 -1.8,-0.31 -2.61,-0.52l0.33,-1.31c1.17,0.29 2.37,0.5 3.61,0.64 1.23,0.13 2.48,0.2 3.74,0.2s2.5,-0.07 3.74,-0.2c1.23,-0.13 2.44,-0.34 3.61,-0.64l0.33,1.31c-0.8,0.2 -1.67,0.38 -2.61,0.52 -0.94,0.14 -1.86,0.24 -2.78,0.32v10.83h-1.31v-5.35h-1.93v5.35h-1.31ZM203.45,80.44c-0.25,0 -0.45,-0.08 -0.6,-0.23 -0.15,-0.15 -0.23,-0.35 -0.23,-0.6 0,-0.25 0.08,-0.45 0.23,-0.6 0.15,-0.15 0.35,-0.23 0.6,-0.23s0.45,0.08 0.6,0.23c0.15,0.15 0.23,0.35 0.23,0.6 0,0.25 -0.08,0.45 -0.23,0.6 -0.15,0.15 -0.35,0.23 -0.6,0.23ZM207.05,80.44c-0.25,0 -0.45,-0.08 -0.6,-0.23 -0.15,-0.15 -0.23,-0.35 -0.23,-0.6 0,-0.25 0.08,-0.45 0.23,-0.6 0.15,-0.15 0.35,-0.23 0.6,-0.23s0.45,0.08 0.6,0.23c0.15,0.15 0.23,0.35 0.23,0.6 0,0.25 -0.08,0.45 -0.23,0.6 -0.15,0.15 -0.35,0.23 -0.6,0.23ZM210.64,80.44c-0.25,0 -0.45,-0.08 -0.6,-0.23 -0.15,-0.15 -0.23,-0.35 -0.23,-0.6 0,-0.25 0.08,-0.45 0.23,-0.6 0.15,-0.15 0.35,-0.23 0.6,-0.23s0.45,0.08 0.6,0.23c0.15,0.15 0.23,0.35 0.23,0.6 0,0.25 -0.08,0.45 -0.23,0.6 -0.15,0.15 -0.35,0.23 -0.6,0.23Z"/>
+ android:pathData="M207.39,53.2c-0.59,0 -1.1,-0.21 -1.53,-0.64 -0.42,-0.42 -0.64,-0.93 -0.64,-1.53s0.21,-1.1 0.64,-1.53c0.42,-0.42 0.93,-0.64 1.53,-0.64s1.1,0.21 1.53,0.64c0.42,0.42 0.64,0.93 0.64,1.53s-0.21,1.1 -0.64,1.53 -0.93,0.64 -1.53,0.64ZM204.31,71.39v-14.63c-1.24,-0.1 -2.5,-0.24 -3.76,-0.43 -1.26,-0.19 -2.44,-0.42 -3.53,-0.7l0.44,-1.78c1.58,0.39 3.2,0.68 4.87,0.86 1.67,0.18 3.35,0.27 5.05,0.27s3.38,-0.09 5.05,-0.27c1.67,-0.18 3.29,-0.46 4.87,-0.86l0.44,1.78c-1.09,0.28 -2.26,0.51 -3.53,0.7 -1.26,0.19 -2.52,0.33 -3.76,0.43v14.63h-1.78v-7.23h-2.61v7.23h-1.78ZM202.56,77.31c-0.34,0 -0.61,-0.1 -0.81,-0.31 -0.21,-0.21 -0.31,-0.48 -0.31,-0.81 0,-0.34 0.1,-0.61 0.31,-0.81 0.21,-0.21 0.48,-0.31 0.81,-0.31s0.61,0.1 0.81,0.31c0.21,0.21 0.31,0.48 0.31,0.81 0,0.34 -0.1,0.61 -0.31,0.81 -0.21,0.21 -0.48,0.31 -0.81,0.31ZM207.42,77.31c-0.34,0 -0.61,-0.1 -0.81,-0.31 -0.21,-0.21 -0.31,-0.48 -0.31,-0.81 0,-0.34 0.1,-0.61 0.31,-0.81 0.21,-0.21 0.48,-0.31 0.81,-0.31s0.61,0.1 0.81,0.31c0.21,0.21 0.31,0.48 0.31,0.81 0,0.34 -0.1,0.61 -0.31,0.81 -0.21,0.21 -0.48,0.31 -0.81,0.31ZM212.28,77.31c-0.34,0 -0.61,-0.1 -0.81,-0.31 -0.21,-0.21 -0.31,-0.48 -0.31,-0.81 0,-0.34 0.1,-0.61 0.31,-0.81 0.21,-0.21 0.48,-0.31 0.81,-0.31s0.61,0.1 0.81,0.31c0.21,0.21 0.31,0.48 0.31,0.81 0,0.34 -0.1,0.61 -0.31,0.81 -0.21,0.21 -0.48,0.31 -0.81,0.31Z"/>
<path
- android:pathData="M141.86,180.81h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M119.3,212.98h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#fdd663"/>
<path
android:fillColor="#FF000000"
- android:pathData="M141.88,209.09l-3.16,-3.06h-4.35v-4.35l-3.13,-3.13 3.13,-3.13v-4.35h4.35l3.16,-3.13 3.11,3.13h4.35v4.35l3.13,3.13 -3.13,3.13v4.35h-4.35l-3.11,3.06ZM141.88,203.08c-1.26,0 -2.34,-0.44 -3.23,-1.33 -0.89,-0.89 -1.33,-1.96 -1.33,-3.23s0.44,-2.34 1.33,-3.23c0.89,-0.89 1.96,-1.33 3.23,-1.33 1.26,0 2.34,0.44 3.23,1.33 0.89,0.89 1.33,1.96 1.33,3.23s-0.44,2.34 -1.33,3.23c-0.89,0.89 -1.96,1.33 -3.23,1.33ZM141.88,201.68c0.89,0 1.64,-0.3 2.24,-0.91 0.61,-0.61 0.91,-1.36 0.91,-2.24 -0,-0.89 -0.3,-1.64 -0.91,-2.24 -0.61,-0.61 -1.36,-0.91 -2.24,-0.91 -0.89,0 -1.64,0.3 -2.24,0.91 -0.61,0.61 -0.91,1.36 -0.91,2.24s0.3,1.64 0.91,2.24c0.61,0.61 1.36,0.91 2.24,0.91ZM141.88,207.12l2.53,-2.5h3.53v-3.53l2.55,-2.55 -2.55,-2.55v-3.53h-3.53l-2.53,-2.55 -2.57,2.55h-3.53v3.53l-2.55,2.55 2.55,2.55v3.53h3.51l2.6,2.5Z"/>
+ android:pathData="M119.34,251.2l-4.27,-4.14h-5.88v-5.88l-4.23,-4.23 4.23,-4.23v-5.88h5.88l4.27,-4.23 4.2,4.23h5.88v5.88l4.23,4.23 -4.23,4.23v5.88h-5.88l-4.2,4.14ZM119.34,243.08c-1.71,0 -3.16,-0.6 -4.36,-1.8 -1.2,-1.2 -1.8,-2.65 -1.8,-4.36s0.6,-3.16 1.8,-4.36c1.2,-1.2 2.65,-1.8 4.36,-1.8 1.71,0 3.16,0.6 4.36,1.8 1.2,1.2 1.8,2.65 1.8,4.36s-0.6,3.16 -1.8,4.36c-1.2,1.2 -2.65,1.8 -4.36,1.8ZM119.34,241.18c1.2,0 2.21,-0.41 3.03,-1.23 0.82,-0.82 1.23,-1.83 1.23,-3.03 -0,-1.2 -0.41,-2.21 -1.23,-3.03 -0.82,-0.82 -1.83,-1.23 -3.03,-1.23 -1.2,0 -2.21,0.41 -3.03,1.23 -0.82,0.82 -1.23,1.83 -1.23,3.03s0.41,2.21 1.23,3.03c0.82,0.82 1.83,1.23 3.03,1.23ZM119.34,248.55l3.41,-3.38h4.77v-4.77l3.44,-3.44 -3.44,-3.44v-4.77h-4.77l-3.41,-3.44 -3.48,3.44h-4.77v4.77l-3.44,3.44 3.44,3.44v4.77h4.74l3.51,3.38Z"/>
<path
- android:pathData="M207.03,180.82h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M207.39,212.99h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#fdd663"/>
<path
android:fillColor="#FF000000"
- android:pathData="M207.05,209.09l-3.16,-3.06h-4.35v-4.35l-3.13,-3.13 3.13,-3.13v-4.35h4.35l3.16,-3.13 3.11,3.13h4.35v4.35l3.13,3.13 -3.13,3.13v4.35h-4.35l-3.11,3.06ZM207.05,203.08c1.26,0 2.34,-0.44 3.23,-1.33 0.89,-0.89 1.33,-1.96 1.33,-3.23s-0.44,-2.34 -1.33,-3.23c-0.89,-0.89 -1.96,-1.33 -3.23,-1.33 -1.26,0 -2.34,0.44 -3.23,1.33 -0.89,0.89 -1.33,1.96 -1.33,3.23s0.44,2.34 1.33,3.23c0.89,0.89 1.96,1.33 3.23,1.33ZM207.05,201.68c0.89,0 1.64,-0.3 2.24,-0.91 0.61,-0.61 0.91,-1.36 0.91,-2.24 -0,-0.89 -0.3,-1.64 -0.91,-2.24 -0.61,-0.61 -1.36,-0.91 -2.24,-0.91 -0.89,0 -1.64,0.3 -2.24,0.91 -0.61,0.61 -0.91,1.36 -0.91,2.24s0.3,1.64 0.91,2.24c0.61,0.61 1.36,0.91 2.24,0.91ZM207.05,207.13l2.53,-2.5h3.53v-3.53l2.55,-2.55 -2.55,-2.55v-3.53h-3.53l-2.53,-2.55 -2.57,2.55h-3.53v3.53l-2.55,2.55 2.55,2.55v3.53h3.51l2.6,2.5ZM207.05,201.68c0.89,0 1.64,-0.3 2.24,-0.91 0.61,-0.61 0.91,-1.36 0.91,-2.24 -0,-0.89 -0.3,-1.64 -0.91,-2.24 -0.61,-0.61 -1.36,-0.91 -2.24,-0.91 -0.89,0 -1.64,0.3 -2.24,0.91 -0.61,0.61 -0.91,1.36 -0.91,2.24s0.3,1.64 0.91,2.24c0.61,0.61 1.36,0.91 2.24,0.91Z"/>
+ android:pathData="M207.42,251.21l-4.27,-4.14h-5.88v-5.88l-4.23,-4.23 4.23,-4.23v-5.88h5.88l4.27,-4.23 4.2,4.23h5.88v5.88l4.23,4.23 -4.23,4.23v5.88h-5.88l-4.2,4.14ZM207.42,243.09c1.71,0 3.16,-0.6 4.36,-1.8 1.2,-1.2 1.8,-2.65 1.8,-4.36s-0.6,-3.16 -1.8,-4.36c-1.2,-1.2 -2.65,-1.8 -4.36,-1.8 -1.71,0 -3.16,0.6 -4.36,1.8 -1.2,1.2 -1.8,2.65 -1.8,4.36s0.6,3.16 1.8,4.36c1.2,1.2 2.65,1.8 4.36,1.8ZM207.42,241.19c1.2,0 2.21,-0.41 3.03,-1.23 0.82,-0.82 1.23,-1.83 1.23,-3.03 -0,-1.2 -0.41,-2.21 -1.23,-3.03 -0.82,-0.82 -1.83,-1.23 -3.03,-1.23 -1.2,0 -2.21,0.41 -3.03,1.23 -0.82,0.82 -1.23,1.83 -1.23,3.03s0.41,2.21 1.23,3.03c0.82,0.82 1.83,1.23 3.03,1.23ZM207.42,248.55l3.41,-3.38h4.77v-4.77l3.44,-3.44 -3.44,-3.44v-4.77h-4.77l-3.41,-3.44 -3.48,3.44h-4.77v4.77l-3.44,3.44 3.44,3.44v4.77h4.74l3.51,3.38ZM207.42,241.19c1.2,0 2.21,-0.41 3.03,-1.23 0.82,-0.82 1.23,-1.83 1.23,-3.03 -0,-1.2 -0.41,-2.21 -1.23,-3.03 -0.82,-0.82 -1.83,-1.23 -3.03,-1.23 -1.2,0 -2.21,0.41 -3.03,1.23 -0.82,0.82 -1.23,1.83 -1.23,3.03s0.41,2.21 1.23,3.03c0.82,0.82 1.83,1.23 3.03,1.23Z"/>
<path
- android:pathData="M270.14,180.81h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M292.7,212.98h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#84e39f"/>
<path
android:fillColor="#FF000000"
- android:pathData="M263.92,207.44c-0.4,0 -0.74,-0.14 -1.02,-0.42s-0.42,-0.62 -0.42,-1.02v-10.37c0,-0.4 0.14,-0.74 0.42,-1.02s0.62,-0.42 1.02,-0.42h1.67v-2.29c0,-1.26 0.44,-2.33 1.33,-3.22 0.88,-0.88 1.96,-1.33 3.22,-1.33s2.33,0.44 3.22,1.33c0.88,0.88 1.33,1.96 1.33,3.22v2.29h1.67c0.4,0 0.74,0.14 1.02,0.42s0.42,0.62 0.42,1.02v10.37c0,0.4 -0.14,0.74 -0.42,1.02s-0.62,0.42 -1.02,0.42h-12.43ZM263.92,206.01h12.43v-10.37h-12.43v10.37ZM270.14,202.66c0.51,0 0.94,-0.18 1.3,-0.53s0.54,-0.77 0.54,-1.27c0,-0.48 -0.18,-0.91 -0.54,-1.3s-0.79,-0.59 -1.3,-0.59 -0.94,0.2 -1.3,0.59c-0.36,0.39 -0.54,0.82 -0.54,1.3 0,0.49 0.18,0.92 0.54,1.27s0.79,0.53 1.3,0.53ZM267.03,194.2h6.22v-2.29c0,-0.86 -0.3,-1.59 -0.91,-2.2 -0.61,-0.61 -1.34,-0.91 -2.2,-0.91s-1.59,0.3 -2.2,0.91 -0.91,1.34 -0.91,2.2v2.29ZM263.92,206.01v0Z"/>
+ android:pathData="M284.29,248.97c-0.54,0 -1,-0.19 -1.37,-0.57s-0.57,-0.83 -0.57,-1.37v-14.02c0,-0.54 0.19,-1 0.57,-1.37s0.83,-0.57 1.37,-0.57h2.26v-3.1c0,-1.7 0.6,-3.15 1.79,-4.35 1.2,-1.2 2.64,-1.79 4.35,-1.79s3.15,0.6 4.35,1.79c1.2,1.2 1.79,2.64 1.79,4.35v3.1h2.26c0.54,0 1,0.19 1.37,0.57s0.57,0.83 0.57,1.37v14.02c0,0.54 -0.19,1 -0.57,1.37s-0.83,0.57 -1.37,0.57h-16.8ZM284.29,247.03h16.8v-14.02h-16.8v14.02ZM292.7,242.51c0.69,0 1.28,-0.24 1.76,-0.71s0.73,-1.04 0.73,-1.71c0,-0.65 -0.24,-1.23 -0.73,-1.76s-1.07,-0.79 -1.76,-0.79 -1.28,0.26 -1.76,0.79c-0.48,0.53 -0.73,1.11 -0.73,1.76 0,0.67 0.24,1.24 0.73,1.71s1.07,0.71 1.76,0.71ZM288.5,231.07h8.4v-3.1c0,-1.16 -0.41,-2.15 -1.23,-2.97 -0.82,-0.82 -1.81,-1.23 -2.97,-1.23s-2.15,0.41 -2.97,1.23 -1.23,1.81 -1.23,2.97v3.1ZM284.29,247.03v0Z"/>
<path
- android:pathData="M207.03,116.5h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M207.39,126.06h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#7ae2d4"/>
<path
android:fillColor="#FF000000"
- android:pathData="M209.17,143.6v-1.66c1.73,-0.5 3.15,-1.46 4.25,-2.88 1.1,-1.42 1.65,-3.03 1.65,-4.84 0,-1.8 -0.54,-3.42 -1.63,-4.85s-2.51,-2.38 -4.26,-2.87v-1.66c2.22,0.5 4.02,1.62 5.41,3.36 1.39,1.74 2.09,3.75 2.09,6.02s-0.7,4.27 -2.09,6.02c-1.39,1.74 -3.2,2.86 -5.41,3.36ZM197.38,137.46v-6.43h4.29l5.36,-5.36v17.15l-5.36,-5.36h-4.29ZM208.63,138.75v-9.03c0.98,0.3 1.76,0.88 2.34,1.71 0.58,0.84 0.87,1.78 0.87,2.81 0,1.02 -0.29,1.95 -0.88,2.79s-1.37,1.41 -2.33,1.71ZM205.42,129.75l-3.03,2.89h-3.4v3.22h3.4l3.03,2.92v-9.03Z"/>
+ android:pathData="M210.29,162.68v-2.25c2.34,-0.68 4.26,-1.97 5.74,-3.89 1.49,-1.92 2.23,-4.1 2.23,-6.54 0,-2.44 -0.74,-4.62 -2.21,-6.56 -1.47,-1.93 -3.39,-3.22 -5.76,-3.88v-2.25c2.99,0.68 5.43,2.19 7.32,4.55 1.88,2.35 2.83,5.06 2.83,8.13s-0.94,5.78 -2.83,8.13c-1.88,2.35 -4.32,3.87 -7.32,4.55ZM194.35,154.39v-8.69h5.8l7.24,-7.24v23.18l-7.24,-7.24h-5.8ZM209.56,156.13v-12.21c1.33,0.41 2.38,1.18 3.17,2.32 0.78,1.13 1.18,2.4 1.18,3.8 0,1.38 -0.4,2.63 -1.2,3.77s-1.85,1.91 -3.15,2.32ZM205.21,143.96l-4.09,3.91h-4.6v4.35h4.6l4.09,3.95v-12.21Z"/>
<path
- android:pathData="M270.14,116.54h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M292.7,126.1h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#efa5de"/>
<path
android:fillColor="#FF000000"
- android:pathData="M275.08,127.12h-9.89v14.23h9.89v-14.23Z"/>
+ android:pathData="M299.38,140.4h-13.36v19.23h13.36v-19.23Z"/>
<path
android:fillColor="#FF000000"
- android:pathData="M263.88,129.91h-3.56v8.76h3.56v-8.76Z"/>
+ android:pathData="M284.23,144.18h-4.81v11.84h4.81v-11.84Z"/>
<path
android:fillColor="#FF000000"
- android:pathData="M279.96,129.91h-3.56v8.76h3.56v-8.76Z"/>
+ android:pathData="M305.97,144.18h-4.81v11.84h4.81v-11.84Z"/>
<path
- android:pathData="M267.04,128.82h6.21v10.83h-6.21z"
+ android:pathData="M288.5,142.7h8.39v14.63h-8.39z"
android:fillColor="#efa5de"/>
<path
- android:pathData="M141.86,116.5h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M119.3,126.06h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#7ae2d4"/>
<path
android:fillColor="#FF000000"
- android:pathData="M134.62,137.44v-6.43h4.29l5.36,-5.36v17.16l-5.36,-5.36h-4.29ZM145.88,138.73v-9.03c0.97,0.3 1.74,0.88 2.33,1.72 0.59,0.84 0.88,1.78 0.88,2.81 0,1.05 -0.29,1.99 -0.88,2.81s-1.37,1.39 -2.33,1.69ZM142.66,129.72l-3.03,2.9h-3.4v3.22h3.4l3.03,2.92v-9.03Z"/>
+ android:pathData="M109.52,154.35v-8.7h5.8l7.25,-7.25v23.19l-7.25,-7.25h-5.8ZM124.74,156.09v-12.21c1.3,0.41 2.36,1.18 3.15,2.32 0.8,1.14 1.2,2.4 1.2,3.8 0,1.43 -0.4,2.69 -1.2,3.8s-1.85,1.87 -3.15,2.28ZM120.39,143.92l-4.09,3.91h-4.6v4.35h4.6l4.09,3.95v-12.21Z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M119.09,78.27l-3.9,-4.01 -5.93,-0.08c-0.53,-0.01 -0.99,-0.21 -1.38,-0.61 -0.39,-0.4 -0.58,-0.86 -0.57,-1.39l0.26,-19.77c0.01,-0.53 0.21,-0.99 0.61,-1.38 0.4,-0.39 0.86,-0.58 1.39,-0.57l19.77,0.26c0.53,0.01 0.99,0.21 1.38,0.61 0.39,0.4 0.58,0.86 0.57,1.39l-0.26,19.77c-0.01,0.53 -0.21,0.99 -0.61,1.38 -0.4,0.39 -0.86,0.58 -1.39,0.57l-5.93,-0.08 -4.01,3.9ZM119.25,68.61l1.9,-4.19 4.24,-1.79 -4.19,-1.9 -1.79,-4.24 -1.93,4.19 -4.21,1.79 4.16,1.9 1.82,4.24Z"/>
</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-sw600dp-night/a11ymenu_intro.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-sw600dp-night/a11ymenu_intro.xml
deleted file mode 100644
index cb2e974..0000000
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-sw600dp-night/a11ymenu_intro.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="412dp"
- android:height="300dp"
- android:viewportWidth="412"
- android:viewportHeight="300">
- <path
- android:fillColor="#FF000000"
- android:pathData="M199.88,53.03l-2.73,-2.73h-4.09c-0.36,0 -0.68,-0.14 -0.95,-0.41 -0.27,-0.27 -0.41,-0.59 -0.41,-0.95v-13.64c0,-0.36 0.14,-0.68 0.41,-0.95 0.27,-0.27 0.59,-0.41 0.95,-0.41h13.64c0.36,0 0.68,0.14 0.95,0.41 0.27,0.27 0.41,0.59 0.41,0.95v13.64c0,0.36 -0.14,0.68 -0.41,0.95 -0.27,0.27 -0.59,0.41 -0.95,0.41h-4.09l-2.73,2.73ZM199.9,46.37l1.27,-2.91 2.91,-1.27 -2.91,-1.27 -1.27,-2.91 -1.3,2.91 -2.89,1.27 2.89,1.27 1.3,2.91Z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M384.18,300H27.82c-15.29,0 -27.82,-12.83 -27.82,-28.48V28.48C0,12.83 12.53,0 27.82,0H384.29c15.18,0 27.71,12.83 27.71,28.48v243.15c0,15.54 -12.53,28.37 -27.82,28.37Z"/>
- <path
- android:pathData="M207.19,52.65h151.18c4.14,0 7.51,3.36 7.51,7.51V243.15c0,4.14 -3.36,7.51 -7.51,7.51H207.19V52.65h0Z"
- android:fillColor="#5f6368"/>
- <path
- android:pathData="M368.24,143.47L368.24,60.55c0,-5.67 -4.59,-10.26 -10.26,-10.26L54.02,50.29c-5.67,0 -10.26,4.59 -10.26,10.26L43.76,242.76c0,5.67 4.59,10.26 10.26,10.26L357.98,253.02c5.67,0 10.26,-4.59 10.26,-10.26v-99.29ZM365.88,243.14c0,4.15 -3.75,7.52 -7.9,7.52L54.02,250.66c-4.15,0 -7.9,-3.37 -7.9,-7.52L46.12,60.55c0,-4.15 3.75,-7.9 7.9,-7.9L357.98,52.65c4.15,0 7.9,3.75 7.9,7.9L365.88,243.14Z"
- android:fillColor="#80868b"/>
- <path
- android:pathData="M319.83,50.29c-0,-1.28 -1.04,-2.31 -2.31,-2.31h-23.11c-1.28,0 -2.31,1.03 -2.31,2.31h27.74Z"
- android:fillColor="#80868b"/>
- <path
- android:pathData="M344.42,50.29c-0,-1.28 -1.03,-2.31 -2.31,-2.31h-9.25c-1.28,0 -2.31,1.03 -2.31,2.31h13.87Z"
- android:fillColor="#80868b"/>
- <path
- android:pathData="M86.06,240.43l0.7,-0.7 -2.7,-2.7h5.9v-1h-5.9l2.7,-2.7 -0.7,-0.7 -3.9,3.9 3.9,3.9Z"
- android:fillColor="#5f6368"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M166.93,232.89l-0.7,0.7 2.7,2.7h-5.9v1h5.9l-2.7,2.7 0.7,0.7 3.9,-3.9 -3.9,-3.9Z"
- android:fillColor="#7f868c"
- android:fillType="evenOdd"/>
- <path
- android:strokeWidth="1"
- android:pathData="M46.12,222.93L207.19,222.93"
- android:fillColor="#00000000"
- android:strokeColor="#5f6368"/>
- <path
- android:strokeWidth="1"
- android:pathData="M126.66,222.93L126.66,250.66"
- android:fillColor="#00000000"
- android:strokeColor="#5f6368"/>
- <path
- android:pathData="M78.55,70.3h0c8.84,0 16,7.16 16,16h0c0,8.84 -7.16,16 -16,16h0c-8.84,0 -16,-7.16 -16,-16h0c0,-8.84 7.16,-16 16,-16Z"
- android:fillColor="#2197f3"/>
- <path
- android:pathData="M78.55,174.3h0c8.83,0 16,7.16 16,16h0c0,8.83 -7.16,16 -16,16h0c-8.83,0 -16,-7.16 -16,-16h0c0,-8.83 7.16,-16 16,-16Z"
- android:fillColor="#fdd663"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M78.57,199.86l-2.85,-2.77h-3.93v-3.93l-2.83,-2.83 2.83,-2.83v-3.93h3.93l2.85,-2.83 2.81,2.83h3.93v3.93l2.83,2.83 -2.83,2.83v3.93h-3.93l-2.81,2.77ZM78.57,194.43c-1.14,0 -2.11,-0.4 -2.92,-1.2 -0.8,-0.8 -1.2,-1.78 -1.2,-2.92s0.4,-2.11 1.2,-2.92c0.8,-0.8 1.78,-1.2 2.92,-1.2 1.14,0 2.11,0.4 2.92,1.2 0.8,0.8 1.2,1.78 1.2,2.92s-0.4,2.11 -1.2,2.92c-0.8,0.8 -1.78,1.2 -2.92,1.2ZM78.57,193.16c0.8,0 1.48,-0.27 2.03,-0.82 0.55,-0.55 0.82,-1.23 0.82,-2.03 -0,-0.8 -0.27,-1.48 -0.82,-2.03 -0.55,-0.55 -1.23,-0.82 -2.03,-0.82 -0.8,0 -1.48,0.27 -2.03,0.82 -0.55,0.55 -0.82,1.23 -0.82,2.03s0.27,1.48 0.82,2.03c0.55,0.55 1.23,0.82 2.03,0.82ZM78.57,198.09l2.28,-2.26h3.19v-3.19l2.3,-2.3 -2.3,-2.3v-3.19h-3.19l-2.28,-2.3 -2.32,2.3h-3.19v3.19l-2.3,2.3 2.3,2.3v3.19h3.17l2.35,2.26Z"/>
- <path
- android:pathData="M126.55,174.31h0c8.83,0 16,7.16 16,16h0c0,8.83 -7.16,16 -16,16h0c-8.83,0 -16,-7.16 -16,-16h0c0,-8.83 7.16,-16 16,-16Z"
- android:fillColor="#fdd663"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M126.58,199.87l-2.85,-2.77h-3.93v-3.93l-2.83,-2.83 2.83,-2.83v-3.93h3.93l2.85,-2.83 2.81,2.83h3.93v3.93l2.83,2.83 -2.83,2.83v3.93h-3.93l-2.81,2.77ZM126.58,194.44c1.14,0 2.11,-0.4 2.92,-1.2 0.8,-0.8 1.2,-1.78 1.2,-2.92s-0.4,-2.11 -1.2,-2.92c-0.8,-0.8 -1.78,-1.2 -2.92,-1.2 -1.14,0 -2.11,0.4 -2.92,1.2 -0.8,0.8 -1.2,1.78 -1.2,2.92s0.4,2.11 1.2,2.92c0.8,0.8 1.78,1.2 2.92,1.2ZM126.58,193.17c0.8,0 1.48,-0.27 2.03,-0.82 0.55,-0.55 0.82,-1.23 0.82,-2.03 -0,-0.8 -0.27,-1.48 -0.82,-2.03 -0.55,-0.55 -1.23,-0.82 -2.03,-0.82 -0.8,0 -1.48,0.27 -2.03,0.82 -0.55,0.55 -0.82,1.23 -0.82,2.03s0.27,1.48 0.82,2.03c0.55,0.55 1.23,0.82 2.03,0.82ZM126.58,198.09l2.28,-2.26h3.19v-3.19l2.3,-2.3 -2.3,-2.3v-3.19h-3.19l-2.28,-2.3 -2.32,2.3h-3.19v3.19l-2.3,2.3 2.3,2.3v3.19h3.17l2.35,2.26ZM126.58,193.17c0.8,0 1.48,-0.27 2.03,-0.82 0.55,-0.55 0.82,-1.23 0.82,-2.03 -0,-0.8 -0.27,-1.48 -0.82,-2.03 -0.55,-0.55 -1.23,-0.82 -2.03,-0.82 -0.8,0 -1.48,0.27 -2.03,0.82 -0.55,0.55 -0.82,1.23 -0.82,2.03s0.27,1.48 0.82,2.03c0.55,0.55 1.23,0.82 2.03,0.82Z"/>
- <path
- android:pathData="M174.56,174.3h0c8.83,0 16,7.16 16,16h0c0,8.83 -7.16,16 -16,16h0c-8.83,0 -16,-7.16 -16,-16h0c0,-8.83 7.16,-16 16,-16Z"
- android:fillColor="#84e39f"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M168.94,198.37c-0.36,0 -0.67,-0.13 -0.92,-0.38s-0.38,-0.56 -0.38,-0.92v-9.38c0,-0.36 0.13,-0.67 0.38,-0.92s0.56,-0.38 0.92,-0.38h1.51v-2.07c0,-1.14 0.4,-2.11 1.2,-2.91 0.8,-0.8 1.77,-1.2 2.91,-1.2s2.11,0.4 2.91,1.2c0.8,0.8 1.2,1.77 1.2,2.91v2.07h1.51c0.36,0 0.67,0.13 0.92,0.38s0.38,0.56 0.38,0.92v9.38c0,0.36 -0.13,0.67 -0.38,0.92s-0.56,0.38 -0.92,0.38h-11.24ZM168.94,197.08h11.24v-9.38h-11.24v9.38ZM174.56,194.05c0.46,0 0.85,-0.16 1.18,-0.48s0.49,-0.7 0.49,-1.15c0,-0.43 -0.16,-0.82 -0.49,-1.18s-0.72,-0.53 -1.18,-0.53 -0.85,0.18 -1.18,0.53c-0.32,0.35 -0.49,0.75 -0.49,1.18 0,0.45 0.16,0.83 0.49,1.15s0.72,0.48 1.18,0.48ZM171.75,186.4h5.62v-2.07c0,-0.78 -0.27,-1.44 -0.82,-1.99 -0.55,-0.55 -1.21,-0.82 -1.99,-0.82s-1.44,0.27 -1.99,0.82 -0.82,1.21 -0.82,1.99v2.07ZM168.94,197.08v0Z"/>
- <path
- android:pathData="M174.56,70.24h0c8.87,0 16.06,7.19 16.06,16.06h0c0,8.87 -7.19,16.06 -16.06,16.06h0c-8.87,0 -16.06,-7.19 -16.06,-16.06h0c0,-8.87 7.19,-16.06 16.06,-16.06Z"
- android:fillColor="#dbdce0"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M173.75,79.12h1.61v7.93h-1.61v-7.93ZM178.07,82.03l1.1,-1.1c1.51,1.31 2.51,3.21 2.51,5.42 0,3.92 -3.21,7.13 -7.13,7.13s-7.13,-3.21 -7.13,-7.13c0,-2.21 1,-4.12 2.51,-5.42l1.1,1.1c-1.2,1 -2.01,2.61 -2.01,4.32 0,3.11 2.51,5.62 5.62,5.62 3.11,0 5.62,-2.51 5.62,-5.62 -0.1,-1.81 -1,-3.31 -2.21,-4.32Z"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M126.55,70.24h0c8.87,0 16.06,7.19 16.06,16.06h0c0,8.87 -7.19,16.06 -16.06,16.06h0c-8.87,0 -16.06,-7.19 -16.06,-16.06h0c0,-8.87 7.19,-16.06 16.06,-16.06Z"
- android:fillColor="#d9affd"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M126.55,79.66c-0.4,0 -0.74,-0.14 -1.02,-0.43 -0.29,-0.29 -0.43,-0.63 -0.43,-1.02s0.14,-0.74 0.43,-1.02c0.29,-0.29 0.63,-0.43 1.02,-0.43s0.74,0.14 1.02,0.43c0.29,0.29 0.43,0.63 0.43,1.02s-0.14,0.74 -0.43,1.02 -0.63,0.43 -1.02,0.43ZM124.49,91.87v-9.83c-0.84,-0.07 -1.68,-0.16 -2.53,-0.29 -0.85,-0.13 -1.64,-0.28 -2.37,-0.47l0.3,-1.19c1.06,0.27 2.15,0.46 3.27,0.58 1.12,0.12 2.25,0.18 3.39,0.18s2.27,-0.06 3.39,-0.18c1.12,-0.12 2.21,-0.31 3.27,-0.58l0.3,1.19c-0.73,0.19 -1.52,0.34 -2.37,0.47 -0.85,0.13 -1.69,0.22 -2.53,0.29v9.83h-1.19v-4.85h-1.75v4.85h-1.19ZM123.31,95.85c-0.23,0 -0.41,-0.07 -0.55,-0.21 -0.14,-0.14 -0.21,-0.32 -0.21,-0.55 0,-0.23 0.07,-0.41 0.21,-0.55 0.14,-0.14 0.32,-0.21 0.55,-0.21s0.41,0.07 0.55,0.21c0.14,0.14 0.21,0.32 0.21,0.55 0,0.23 -0.07,0.41 -0.21,0.55 -0.14,0.14 -0.32,0.21 -0.55,0.21ZM126.57,95.85c-0.23,0 -0.41,-0.07 -0.55,-0.21 -0.14,-0.14 -0.21,-0.32 -0.21,-0.55 0,-0.23 0.07,-0.41 0.21,-0.55 0.14,-0.14 0.32,-0.21 0.55,-0.21s0.41,0.07 0.55,0.21c0.14,0.14 0.21,0.32 0.21,0.55 0,0.23 -0.07,0.41 -0.21,0.55 -0.14,0.14 -0.32,0.21 -0.55,0.21ZM129.84,95.85c-0.23,0 -0.41,-0.07 -0.55,-0.21 -0.14,-0.14 -0.21,-0.32 -0.21,-0.55 0,-0.23 0.07,-0.41 0.21,-0.55 0.14,-0.14 0.32,-0.21 0.55,-0.21s0.41,0.07 0.55,0.21c0.14,0.14 0.21,0.32 0.21,0.55 0,0.23 -0.07,0.41 -0.21,0.55 -0.14,0.14 -0.32,0.21 -0.55,0.21Z"/>
- <path
- android:pathData="M126.55,122.3h0c8.83,0 15.99,7.16 15.99,15.99h0c0,8.83 -7.16,15.99 -15.99,15.99h0c-8.83,0 -15.99,-7.16 -15.99,-15.99h0c0,-8.83 7.16,-15.99 15.99,-15.99Z"
- android:fillColor="#7ae2d4"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M128.49,146.78v-1.5c1.57,-0.45 2.84,-1.32 3.84,-2.6 0.99,-1.28 1.49,-2.74 1.49,-4.37 0,-1.63 -0.49,-3.09 -1.48,-4.38s-2.27,-2.15 -3.85,-2.59v-1.5c2,0.45 3.63,1.46 4.89,3.04 1.26,1.57 1.89,3.39 1.89,5.43s-0.63,3.86 -1.89,5.43c-1.26,1.57 -2.89,2.59 -4.89,3.04ZM117.84,141.24v-5.81h3.87l4.84,-4.84v15.49l-4.84,-4.84h-3.87ZM128.01,142.4v-8.16c0.89,0.27 1.59,0.79 2.12,1.55 0.52,0.76 0.79,1.61 0.79,2.54 0,0.92 -0.27,1.76 -0.8,2.52s-1.23,1.28 -2.11,1.55ZM125.1,134.26l-2.74,2.61h-3.07v2.91h3.07l2.74,2.64v-8.16Z"/>
- <path
- android:pathData="M174.56,122.33h0c8.83,0 15.99,7.16 15.99,15.99h0c0,8.83 -7.16,15.99 -15.99,15.99h0c-8.83,0 -15.99,-7.16 -15.99,-15.99h0c0,-8.83 7.16,-15.99 15.99,-15.99Z"
- android:fillColor="#efa5de"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M179.02,131.89h-8.93v12.86h8.93v-12.86Z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M168.9,134.41h-3.22v7.91h3.22v-7.91Z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M183.43,134.41h-3.22v7.91h3.22v-7.91Z"/>
- <path
- android:pathData="M171.75,133.42h5.61v9.78h-5.61z"
- android:fillColor="#efa5de"/>
- <path
- android:pathData="M78.55,122.3h0c8.83,0 15.99,7.16 15.99,15.99h0c0,8.83 -7.16,15.99 -15.99,15.99h0c-8.83,0 -15.99,-7.16 -15.99,-15.99h0c0,-8.83 7.16,-15.99 15.99,-15.99Z"
- android:fillColor="#7ae2d4"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M72.01,141.21v-5.81h3.88l4.84,-4.84v15.5l-4.84,-4.84h-3.88ZM82.18,142.38v-8.16c0.87,0.27 1.57,0.79 2.11,1.55 0.53,0.76 0.8,1.61 0.8,2.54 0,0.95 -0.27,1.8 -0.8,2.54 -0.53,0.74 -1.24,1.25 -2.11,1.53ZM79.28,134.24l-2.74,2.62h-3.08v2.91h3.08l2.74,2.64v-8.16Z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M78.73,96.45l-2.73,-2.73h-4.09c-0.36,0 -0.68,-0.14 -0.95,-0.41 -0.27,-0.27 -0.41,-0.59 -0.41,-0.95v-13.64c0,-0.36 0.14,-0.68 0.41,-0.95 0.27,-0.27 0.59,-0.41 0.95,-0.41h13.64c0.36,0 0.68,0.14 0.95,0.41 0.27,0.27 0.41,0.59 0.41,0.95v13.64c0,0.36 -0.14,0.68 -0.41,0.95 -0.27,0.27 -0.59,0.41 -0.95,0.41h-4.09l-2.73,2.73ZM78.75,89.79l1.27,-2.91 2.91,-1.27 -2.91,-1.27 -1.27,-2.91 -1.3,2.91 -2.89,1.27 2.89,1.27 1.3,2.91Z"/>
-</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-sw600dp/a11ymenu_intro.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-sw600dp/a11ymenu_intro.xml
deleted file mode 100644
index aba9581..0000000
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable-sw600dp/a11ymenu_intro.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="412dp"
- android:height="300dp"
- android:viewportWidth="412"
- android:viewportHeight="300">
- <path
- android:pathData="M384.18,300H27.82c-15.29,0 -27.82,-12.83 -27.82,-28.48V28.48C0,12.83 12.53,0 27.82,0H384.29c15.18,0 27.71,12.83 27.71,28.48v243.15c0,15.54 -12.53,28.37 -27.82,28.37Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M78.71,69.91h0c8.84,0 16,7.16 16,16h0c0,8.84 -7.16,16 -16,16h0c-8.84,0 -16,-7.16 -16,-16h0c0,-8.84 7.16,-16 16,-16Z"
- android:fillColor="#2197f3"/>
- <path
- android:pathData="M207.35,52.26h151.18c4.14,0 7.51,3.36 7.51,7.51V242.76c0,4.14 -3.36,7.51 -7.51,7.51H207.35V52.26h0Z"
- android:fillColor="#e8eaed"/>
- <path
- android:pathData="M368.4,143.08L368.4,60.16c0,-5.67 -4.59,-10.26 -10.26,-10.26L54.17,49.9c-5.67,0 -10.26,4.59 -10.26,10.26L43.91,242.37c0,5.67 4.59,10.26 10.26,10.26L358.14,252.63c5.67,0 10.26,-4.59 10.26,-10.26v-99.29ZM366.04,242.75c0,4.15 -3.75,7.52 -7.9,7.52L54.17,250.27c-4.15,0 -7.9,-3.37 -7.9,-7.52L46.27,60.16c0,-4.15 3.75,-7.9 7.9,-7.9L358.14,52.26c4.15,0 7.9,3.75 7.9,7.9L366.04,242.75Z"
- android:fillColor="#dadce0"/>
- <path
- android:pathData="M319.98,49.9c-0,-1.28 -1.04,-2.31 -2.31,-2.31h-23.11c-1.28,0 -2.31,1.03 -2.31,2.31h27.74Z"
- android:fillColor="#dadce0"/>
- <path
- android:pathData="M344.57,49.9c-0,-1.28 -1.03,-2.31 -2.31,-2.31h-9.25c-1.28,0 -2.31,1.03 -2.31,2.31h13.87Z"
- android:fillColor="#dadce0"/>
- <path
- android:pathData="M86.21,240.04l0.7,-0.7 -2.7,-2.7h5.9v-1h-5.9l2.7,-2.7 -0.7,-0.7 -3.9,3.9 3.9,3.9Z"
- android:fillColor="#e8eaed"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M167.08,232.5l-0.7,0.7 2.7,2.7h-5.9v1h5.9l-2.7,2.7 0.7,0.7 3.9,-3.9 -3.9,-3.9Z"
- android:fillColor="#7f868c"
- android:fillType="evenOdd"/>
- <path
- android:strokeWidth="1"
- android:pathData="M46.27,222.54L207.35,222.54"
- android:fillColor="#00000000"
- android:strokeColor="#e8eaed"/>
- <path
- android:strokeWidth="1"
- android:pathData="M126.81,222.54L126.81,250.27"
- android:fillColor="#00000000"
- android:strokeColor="#e8eaed"/>
- <path
- android:pathData="M78.71,173.91h0c8.83,0 16,7.16 16,16h0c0,8.83 -7.16,16 -16,16h0c-8.83,0 -16,-7.16 -16,-16h0c0,-8.83 7.16,-16 16,-16Z"
- android:fillColor="#de9834"/>
- <path
- android:pathData="M78.73,199.47l-2.85,-2.77h-3.93v-3.93l-2.83,-2.83 2.83,-2.83v-3.93h3.93l2.85,-2.83 2.81,2.83h3.93v3.93l2.83,2.83 -2.83,2.83v3.93h-3.93l-2.81,2.77ZM78.73,194.04c-1.14,0 -2.11,-0.4 -2.92,-1.2 -0.8,-0.8 -1.2,-1.78 -1.2,-2.92s0.4,-2.11 1.2,-2.92c0.8,-0.8 1.78,-1.2 2.92,-1.2 1.14,0 2.11,0.4 2.92,1.2 0.8,0.8 1.2,1.78 1.2,2.92s-0.4,2.11 -1.2,2.92c-0.8,0.8 -1.78,1.2 -2.92,1.2ZM78.73,192.77c0.8,0 1.48,-0.27 2.03,-0.82 0.55,-0.55 0.82,-1.23 0.82,-2.03 -0,-0.8 -0.27,-1.48 -0.82,-2.03 -0.55,-0.55 -1.23,-0.82 -2.03,-0.82 -0.8,0 -1.48,0.27 -2.03,0.82 -0.55,0.55 -0.82,1.23 -0.82,2.03s0.27,1.48 0.82,2.03c0.55,0.55 1.23,0.82 2.03,0.82ZM78.73,197.7l2.28,-2.26h3.19v-3.19l2.3,-2.3 -2.3,-2.3v-3.19h-3.19l-2.28,-2.3 -2.32,2.3h-3.19v3.19l-2.3,2.3 2.3,2.3v3.19h3.17l2.35,2.26Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M126.71,173.92h0c8.83,0 16,7.16 16,16h0c0,8.83 -7.16,16 -16,16h0c-8.83,0 -16,-7.16 -16,-16h0c0,-8.83 7.16,-16 16,-16Z"
- android:fillColor="#de9834"/>
- <path
- android:pathData="M126.73,199.48l-2.85,-2.77h-3.93v-3.93l-2.83,-2.83 2.83,-2.83v-3.93h3.93l2.85,-2.83 2.81,2.83h3.93v3.93l2.83,2.83 -2.83,2.83v3.93h-3.93l-2.81,2.77ZM126.73,194.04c1.14,0 2.11,-0.4 2.92,-1.2 0.8,-0.8 1.2,-1.78 1.2,-2.92s-0.4,-2.11 -1.2,-2.92c-0.8,-0.8 -1.78,-1.2 -2.92,-1.2 -1.14,0 -2.11,0.4 -2.92,1.2 -0.8,0.8 -1.2,1.78 -1.2,2.92s0.4,2.11 1.2,2.92c0.8,0.8 1.78,1.2 2.92,1.2ZM126.73,192.78c0.8,0 1.48,-0.27 2.03,-0.82 0.55,-0.55 0.82,-1.23 0.82,-2.03 -0,-0.8 -0.27,-1.48 -0.82,-2.03 -0.55,-0.55 -1.23,-0.82 -2.03,-0.82 -0.8,0 -1.48,0.27 -2.03,0.82 -0.55,0.55 -0.82,1.23 -0.82,2.03s0.27,1.48 0.82,2.03c0.55,0.55 1.23,0.82 2.03,0.82ZM126.73,197.7l2.28,-2.26h3.19v-3.19l2.3,-2.3 -2.3,-2.3v-3.19h-3.19l-2.28,-2.3 -2.32,2.3h-3.19v3.19l-2.3,2.3 2.3,2.3v3.19h3.17l2.35,2.26ZM126.73,192.78c0.8,0 1.48,-0.27 2.03,-0.82 0.55,-0.55 0.82,-1.23 0.82,-2.03 -0,-0.8 -0.27,-1.48 -0.82,-2.03 -0.55,-0.55 -1.23,-0.82 -2.03,-0.82 -0.8,0 -1.48,0.27 -2.03,0.82 -0.55,0.55 -0.82,1.23 -0.82,2.03s0.27,1.48 0.82,2.03c0.55,0.55 1.23,0.82 2.03,0.82Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M174.71,173.91h0c8.83,0 16,7.16 16,16h0c0,8.83 -7.16,16 -16,16h0c-8.83,0 -16,-7.16 -16,-16h0c0,-8.83 7.16,-16 16,-16Z"
- android:fillColor="#438947"/>
- <path
- android:pathData="M169.09,197.98c-0.36,0 -0.67,-0.13 -0.92,-0.38s-0.38,-0.56 -0.38,-0.92v-9.38c0,-0.36 0.13,-0.67 0.38,-0.92s0.56,-0.38 0.92,-0.38h1.51v-2.07c0,-1.14 0.4,-2.11 1.2,-2.91 0.8,-0.8 1.77,-1.2 2.91,-1.2s2.11,0.4 2.91,1.2c0.8,0.8 1.2,1.77 1.2,2.91v2.07h1.51c0.36,0 0.67,0.13 0.92,0.38s0.38,0.56 0.38,0.92v9.38c0,0.36 -0.13,0.67 -0.38,0.92s-0.56,0.38 -0.92,0.38h-11.24ZM169.09,196.68h11.24v-9.38h-11.24v9.38ZM174.71,193.66c0.46,0 0.85,-0.16 1.18,-0.48s0.49,-0.7 0.49,-1.15c0,-0.43 -0.16,-0.82 -0.49,-1.18s-0.72,-0.53 -1.18,-0.53 -0.85,0.18 -1.18,0.53c-0.32,0.35 -0.49,0.75 -0.49,1.18 0,0.45 0.16,0.83 0.49,1.15s0.72,0.48 1.18,0.48ZM171.9,186.01h5.62v-2.07c0,-0.78 -0.27,-1.44 -0.82,-1.99 -0.55,-0.55 -1.21,-0.82 -1.99,-0.82s-1.44,0.27 -1.99,0.82 -0.82,1.21 -0.82,1.99v2.07ZM169.09,196.68v0Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M174.71,69.85h0c8.87,0 16.06,7.19 16.06,16.06h0c0,8.87 -7.19,16.06 -16.06,16.06h0c-8.87,0 -16.06,-7.19 -16.06,-16.06h0c0,-8.87 7.19,-16.06 16.06,-16.06Z"
- android:fillColor="#80868b"/>
- <path
- android:pathData="M173.91,78.73h1.61v7.93h-1.61v-7.93ZM178.22,81.64l1.1,-1.1c1.51,1.31 2.51,3.21 2.51,5.42 0,3.92 -3.21,7.13 -7.13,7.13s-7.13,-3.21 -7.13,-7.13c0,-2.21 1,-4.12 2.51,-5.42l1.1,1.1c-1.2,1 -2.01,2.61 -2.01,4.32 0,3.11 2.51,5.62 5.62,5.62 3.11,0 5.62,-2.51 5.62,-5.62 -0.1,-1.81 -1,-3.31 -2.21,-4.32Z"
- android:fillColor="#fff"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M126.71,69.85h0c8.87,0 16.06,7.19 16.06,16.06h0c0,8.87 -7.19,16.06 -16.06,16.06h0c-8.87,0 -16.06,-7.19 -16.06,-16.06h0c0,-8.87 7.19,-16.06 16.06,-16.06Z"
- android:fillColor="#521bbf"/>
- <path
- android:pathData="M126.71,79.26c-0.4,0 -0.74,-0.14 -1.02,-0.43 -0.29,-0.29 -0.43,-0.63 -0.43,-1.02s0.14,-0.74 0.43,-1.02c0.29,-0.29 0.63,-0.43 1.02,-0.43s0.74,0.14 1.02,0.43c0.29,0.29 0.43,0.63 0.43,1.02s-0.14,0.74 -0.43,1.02 -0.63,0.43 -1.02,0.43ZM124.64,91.48v-9.83c-0.84,-0.07 -1.68,-0.16 -2.53,-0.29 -0.85,-0.13 -1.64,-0.28 -2.37,-0.47l0.3,-1.19c1.06,0.27 2.15,0.46 3.27,0.58 1.12,0.12 2.25,0.18 3.39,0.18s2.27,-0.06 3.39,-0.18c1.12,-0.12 2.21,-0.31 3.27,-0.58l0.3,1.19c-0.73,0.19 -1.52,0.34 -2.37,0.47 -0.85,0.13 -1.69,0.22 -2.53,0.29v9.83h-1.19v-4.85h-1.75v4.85h-1.19ZM123.47,95.46c-0.23,0 -0.41,-0.07 -0.55,-0.21 -0.14,-0.14 -0.21,-0.32 -0.21,-0.55 0,-0.23 0.07,-0.41 0.21,-0.55 0.14,-0.14 0.32,-0.21 0.55,-0.21s0.41,0.07 0.55,0.21c0.14,0.14 0.21,0.32 0.21,0.55 0,0.23 -0.07,0.41 -0.21,0.55 -0.14,0.14 -0.32,0.21 -0.55,0.21ZM126.73,95.46c-0.23,0 -0.41,-0.07 -0.55,-0.21 -0.14,-0.14 -0.21,-0.32 -0.21,-0.55 0,-0.23 0.07,-0.41 0.21,-0.55 0.14,-0.14 0.32,-0.21 0.55,-0.21s0.41,0.07 0.55,0.21c0.14,0.14 0.21,0.32 0.21,0.55 0,0.23 -0.07,0.41 -0.21,0.55 -0.14,0.14 -0.32,0.21 -0.55,0.21ZM129.99,95.46c-0.23,0 -0.41,-0.07 -0.55,-0.21 -0.14,-0.14 -0.21,-0.32 -0.21,-0.55 0,-0.23 0.07,-0.41 0.21,-0.55 0.14,-0.14 0.32,-0.21 0.55,-0.21s0.41,0.07 0.55,0.21c0.14,0.14 0.21,0.32 0.21,0.55 0,0.23 -0.07,0.41 -0.21,0.55 -0.14,0.14 -0.32,0.21 -0.55,0.21Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M126.71,121.91h0c8.83,0 15.99,7.16 15.99,15.99h0c0,8.83 -7.16,15.99 -15.99,15.99h0c-8.83,0 -15.99,-7.16 -15.99,-15.99h0c0,-8.83 7.16,-15.99 15.99,-15.99Z"
- android:fillColor="#327969"/>
- <path
- android:pathData="M128.65,146.39v-1.5c1.57,-0.45 2.84,-1.32 3.84,-2.6 0.99,-1.28 1.49,-2.74 1.49,-4.37 0,-1.63 -0.49,-3.09 -1.48,-4.38s-2.27,-2.15 -3.85,-2.59v-1.5c2,0.45 3.63,1.46 4.89,3.04 1.26,1.57 1.89,3.39 1.89,5.43s-0.63,3.86 -1.89,5.43c-1.26,1.57 -2.89,2.59 -4.89,3.04ZM117.99,140.84v-5.81h3.87l4.84,-4.84v15.49l-4.84,-4.84h-3.87ZM128.16,142.01v-8.16c0.89,0.27 1.59,0.79 2.12,1.55 0.52,0.76 0.79,1.61 0.79,2.54 0,0.92 -0.27,1.76 -0.8,2.52s-1.23,1.28 -2.11,1.55ZM125.26,133.87l-2.74,2.61h-3.07v2.91h3.07l2.74,2.64v-8.16Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M174.71,121.94h0c8.83,0 15.99,7.16 15.99,15.99h0c0,8.83 -7.16,15.99 -15.99,15.99h0c-8.83,0 -15.99,-7.16 -15.99,-15.99h0c0,-8.83 7.16,-15.99 15.99,-15.99Z"
- android:fillColor="#9f3ebf"/>
- <path
- android:pathData="M179.18,131.5h-8.93v12.86h8.93v-12.86Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M169.05,134.02h-3.22v7.91h3.22v-7.91Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M183.58,134.02h-3.22v7.91h3.22v-7.91Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M171.91,133.03h5.61v9.78h-5.61z"
- android:fillColor="#9f3ebf"/>
- <path
- android:pathData="M78.71,121.91h0c8.83,0 15.99,7.16 15.99,15.99h0c0,8.83 -7.16,15.99 -15.99,15.99h0c-8.83,0 -15.99,-7.16 -15.99,-15.99h0c0,-8.83 7.16,-15.99 15.99,-15.99Z"
- android:fillColor="#327969"/>
- <path
- android:pathData="M72.17,140.82v-5.81h3.88l4.84,-4.84v15.5l-4.84,-4.84h-3.88ZM82.34,141.98v-8.16c0.87,0.27 1.57,0.79 2.11,1.55 0.53,0.76 0.8,1.61 0.8,2.54 0,0.95 -0.27,1.8 -0.8,2.54 -0.53,0.74 -1.24,1.25 -2.11,1.53ZM79.43,133.85l-2.74,2.62h-3.08v2.91h3.08l2.74,2.64v-8.16Z"
- android:fillColor="#fff"/>
- <path
- android:pathData="M78.73,96.45l-2.73,-2.73h-4.09c-0.36,0 -0.68,-0.14 -0.95,-0.41 -0.27,-0.27 -0.41,-0.59 -0.41,-0.95v-13.64c0,-0.36 0.14,-0.68 0.41,-0.95 0.27,-0.27 0.59,-0.41 0.95,-0.41h13.64c0.36,0 0.68,0.14 0.95,0.41 0.27,0.27 0.41,0.59 0.41,0.95v13.64c0,0.36 -0.14,0.68 -0.41,0.95 -0.27,0.27 -0.59,0.41 -0.95,0.41h-4.09l-2.73,2.73ZM78.75,89.79l1.27,-2.91 2.91,-1.27 -2.91,-1.27 -1.27,-2.91 -1.3,2.91 -2.89,1.27 2.89,1.27 1.3,2.91Z"
- android:fillColor="#fff"/>
-</vector>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/a11ymenu_intro.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/a11ymenu_intro.xml
index a5a0535..7cc5d53 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/a11ymenu_intro.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/a11ymenu_intro.xml
@@ -1,90 +1,73 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="412dp"
- android:height="299.24dp"
+ android:height="300dp"
android:viewportWidth="412"
- android:viewportHeight="299.24">
+ android:viewportHeight="300">
<path
- android:pathData="M383.9,299.24H28.1c-15.5,0 -28.1,-12.57 -28.1,-28.03V28.03C0,12.57 12.6,0 28.1,0H383.9c15.5,0 28.1,12.57 28.1,28.03v243.18c0,15.46 -12.6,28.03 -28.1,28.03Z"
+ android:pathData="M383.9,300H28.1c-15.5,0 -28.1,-12.6 -28.1,-28.1V28.1C0,12.6 12.6,0 28.1,0H383.9c15.5,0 28.1,12.6 28.1,28.1v243.8c0,15.5 -12.6,28.1 -28.1,28.1Z"
android:fillColor="#fff"/>
<path
- android:pathData="M106.4,0h195.3c2,0 3.6,0.2 3.6,0.4V31.2c0,0.2 -1.6,0.4 -3.6,0.4H106.4c-2,0 -3.6,-0.2 -3.6,-0.4V0.4c0,-0.2 1.6,-0.4 3.6,-0.4Z"
- android:fillColor="#e8eaed"/>
- <path
- android:pathData="M303.7,238.9H104.5v1h98.4v29.5h1v-29.5h99.8v-1Z"
- android:fillColor="#e8eaed"/>
- <path
- android:pathData="M153.7,258.3l0.7,-0.7 -2.7,-2.7h5.9v-1h-5.9l2.7,-2.7 -0.7,-0.7 -3.9,3.9 3.9,3.9Z"
- android:fillColor="#e8eaed"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M253.5,250.4l-0.7,0.7 2.7,2.7h-5.9v1h5.9l-2.7,2.7 0.7,0.7 3.9,-3.9 -3.9,-3.9Z"
- android:fillColor="#7f868c"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M119.3,273h169.8c10.2,0 18.5,-8.3 18.5,-18.5V73.7c2,0 3.7,-1.7 3.7,-3.7V33.1c0,-2 -1.7,-3.7 -3.7,-3.7V0h-3.7V254.5c0,8.1 -6.6,14.8 -14.8,14.8H119.3c-8.1,0 -14.8,-6.6 -14.8,-14.8V0h-3.7V254.5c0,10.2 8.3,18.5 18.5,18.5Z"
- android:fillColor="#dadce0"/>
- <path
- android:pathData="M141.86,52.23h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M119.3,39.17h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#2197f3"/>
<path
- android:pathData="M270.14,52.23h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M292.7,39.17h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#80868b"/>
<path
- android:pathData="M269.25,62.01h1.77v8.74h-1.77v-8.74ZM274.01,65.22l1.22,-1.22c1.66,1.44 2.76,3.54 2.76,5.97 0,4.31 -3.54,7.85 -7.85,7.85s-7.85,-3.54 -7.85,-7.85c0,-2.43 1.11,-4.53 2.76,-5.97l1.22,1.22c-1.33,1.11 -2.21,2.88 -2.21,4.76 0,3.43 2.76,6.19 6.19,6.19 3.43,0 6.19,-2.76 6.19,-6.19 -0.11,-1.99 -1.11,-3.65 -2.43,-4.76Z"
+ android:pathData="M291.5,52.4h2.39v11.81h-2.39v-11.81ZM297.93,56.74l1.64,-1.64c2.24,1.94 3.74,4.78 3.74,8.07 0,5.83 -4.78,10.61 -10.61,10.61s-10.61,-4.78 -10.61,-10.61c0,-3.29 1.49,-6.13 3.74,-8.07l1.64,1.64c-1.79,1.49 -2.99,3.89 -2.99,6.43 0,4.63 3.74,8.37 8.37,8.37 4.63,0 8.37,-3.74 8.37,-8.37 -0.15,-2.69 -1.49,-4.93 -3.29,-6.43Z"
android:fillColor="#fff"
android:fillType="evenOdd"/>
<path
- android:pathData="M207.03,52.23h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M207.39,39.17h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#521bbf"/>
<path
- android:pathData="M207.03,62.6c-0.44,0 -0.81,-0.16 -1.13,-0.47 -0.31,-0.31 -0.47,-0.69 -0.47,-1.13s0.16,-0.81 0.47,-1.13c0.31,-0.31 0.69,-0.47 1.13,-0.47s0.81,0.16 1.13,0.47c0.31,0.31 0.47,0.69 0.47,1.13s-0.16,0.81 -0.47,1.13 -0.69,0.47 -1.13,0.47ZM204.75,76.06v-10.83c-0.92,-0.07 -1.85,-0.18 -2.78,-0.32 -0.94,-0.14 -1.8,-0.31 -2.61,-0.52l0.33,-1.31c1.17,0.29 2.37,0.5 3.61,0.64 1.23,0.13 2.48,0.2 3.74,0.2s2.5,-0.07 3.74,-0.2c1.23,-0.13 2.44,-0.34 3.61,-0.64l0.33,1.31c-0.8,0.2 -1.67,0.38 -2.61,0.52 -0.94,0.14 -1.86,0.24 -2.78,0.32v10.83h-1.31v-5.35h-1.93v5.35h-1.31ZM203.45,80.44c-0.25,0 -0.45,-0.08 -0.6,-0.23 -0.15,-0.15 -0.23,-0.35 -0.23,-0.6 0,-0.25 0.08,-0.45 0.23,-0.6 0.15,-0.15 0.35,-0.23 0.6,-0.23s0.45,0.08 0.6,0.23c0.15,0.15 0.23,0.35 0.23,0.6 0,0.25 -0.08,0.45 -0.23,0.6 -0.15,0.15 -0.35,0.23 -0.6,0.23ZM207.05,80.44c-0.25,0 -0.45,-0.08 -0.6,-0.23 -0.15,-0.15 -0.23,-0.35 -0.23,-0.6 0,-0.25 0.08,-0.45 0.23,-0.6 0.15,-0.15 0.35,-0.23 0.6,-0.23s0.45,0.08 0.6,0.23c0.15,0.15 0.23,0.35 0.23,0.6 0,0.25 -0.08,0.45 -0.23,0.6 -0.15,0.15 -0.35,0.23 -0.6,0.23ZM210.64,80.44c-0.25,0 -0.45,-0.08 -0.6,-0.23 -0.15,-0.15 -0.23,-0.35 -0.23,-0.6 0,-0.25 0.08,-0.45 0.23,-0.6 0.15,-0.15 0.35,-0.23 0.6,-0.23s0.45,0.08 0.6,0.23c0.15,0.15 0.23,0.35 0.23,0.6 0,0.25 -0.08,0.45 -0.23,0.6 -0.15,0.15 -0.35,0.23 -0.6,0.23Z"
+ android:pathData="M207.39,53.2c-0.59,0 -1.1,-0.21 -1.53,-0.64 -0.42,-0.42 -0.64,-0.93 -0.64,-1.53s0.21,-1.1 0.64,-1.53c0.42,-0.42 0.93,-0.64 1.53,-0.64s1.1,0.21 1.53,0.64c0.42,0.42 0.64,0.93 0.64,1.53s-0.21,1.1 -0.64,1.53 -0.93,0.64 -1.53,0.64ZM204.31,71.39v-14.63c-1.24,-0.1 -2.5,-0.24 -3.76,-0.43 -1.26,-0.19 -2.44,-0.42 -3.53,-0.7l0.44,-1.78c1.58,0.39 3.2,0.68 4.87,0.86 1.67,0.18 3.35,0.27 5.05,0.27s3.38,-0.09 5.05,-0.27c1.67,-0.18 3.29,-0.46 4.87,-0.86l0.44,1.78c-1.09,0.28 -2.26,0.51 -3.53,0.7 -1.26,0.19 -2.52,0.33 -3.76,0.43v14.63h-1.78v-7.23h-2.61v7.23h-1.78ZM202.56,77.31c-0.34,0 -0.61,-0.1 -0.81,-0.31 -0.21,-0.21 -0.31,-0.48 -0.31,-0.81 0,-0.34 0.1,-0.61 0.31,-0.81 0.21,-0.21 0.48,-0.31 0.81,-0.31s0.61,0.1 0.81,0.31c0.21,0.21 0.31,0.48 0.31,0.81 0,0.34 -0.1,0.61 -0.31,0.81 -0.21,0.21 -0.48,0.31 -0.81,0.31ZM207.42,77.31c-0.34,0 -0.61,-0.1 -0.81,-0.31 -0.21,-0.21 -0.31,-0.48 -0.31,-0.81 0,-0.34 0.1,-0.61 0.31,-0.81 0.21,-0.21 0.48,-0.31 0.81,-0.31s0.61,0.1 0.81,0.31c0.21,0.21 0.31,0.48 0.31,0.81 0,0.34 -0.1,0.61 -0.31,0.81 -0.21,0.21 -0.48,0.31 -0.81,0.31ZM212.28,77.31c-0.34,0 -0.61,-0.1 -0.81,-0.31 -0.21,-0.21 -0.31,-0.48 -0.31,-0.81 0,-0.34 0.1,-0.61 0.31,-0.81 0.21,-0.21 0.48,-0.31 0.81,-0.31s0.61,0.1 0.81,0.31c0.21,0.21 0.31,0.48 0.31,0.81 0,0.34 -0.1,0.61 -0.31,0.81 -0.21,0.21 -0.48,0.31 -0.81,0.31Z"
android:fillColor="#fff"/>
<path
- android:pathData="M141.86,180.81h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M119.3,212.98h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#de9834"/>
<path
- android:pathData="M141.88,209.09l-3.16,-3.06h-4.35v-4.35l-3.13,-3.13 3.13,-3.13v-4.35h4.35l3.16,-3.13 3.11,3.13h4.35v4.35l3.13,3.13 -3.13,3.13v4.35h-4.35l-3.11,3.06ZM141.88,203.08c-1.26,0 -2.34,-0.44 -3.23,-1.33 -0.89,-0.89 -1.33,-1.96 -1.33,-3.23s0.44,-2.34 1.33,-3.23c0.89,-0.89 1.96,-1.33 3.23,-1.33 1.26,0 2.34,0.44 3.23,1.33 0.89,0.89 1.33,1.96 1.33,3.23s-0.44,2.34 -1.33,3.23c-0.89,0.89 -1.96,1.33 -3.23,1.33ZM141.88,201.68c0.89,0 1.64,-0.3 2.24,-0.91 0.61,-0.61 0.91,-1.36 0.91,-2.24 -0,-0.89 -0.3,-1.64 -0.91,-2.24 -0.61,-0.61 -1.36,-0.91 -2.24,-0.91 -0.89,0 -1.64,0.3 -2.24,0.91 -0.61,0.61 -0.91,1.36 -0.91,2.24s0.3,1.64 0.91,2.24c0.61,0.61 1.36,0.91 2.24,0.91ZM141.88,207.12l2.53,-2.5h3.53v-3.53l2.55,-2.55 -2.55,-2.55v-3.53h-3.53l-2.53,-2.55 -2.57,2.55h-3.53v3.53l-2.55,2.55 2.55,2.55v3.53h3.51l2.6,2.5Z"
+ android:pathData="M119.34,251.2l-4.27,-4.14h-5.88v-5.88l-4.23,-4.23 4.23,-4.23v-5.88h5.88l4.27,-4.23 4.2,4.23h5.88v5.88l4.23,4.23 -4.23,4.23v5.88h-5.88l-4.2,4.14ZM119.34,243.08c-1.71,0 -3.16,-0.6 -4.36,-1.8 -1.2,-1.2 -1.8,-2.65 -1.8,-4.36s0.6,-3.16 1.8,-4.36c1.2,-1.2 2.65,-1.8 4.36,-1.8 1.71,0 3.16,0.6 4.36,1.8 1.2,1.2 1.8,2.65 1.8,4.36s-0.6,3.16 -1.8,4.36c-1.2,1.2 -2.65,1.8 -4.36,1.8ZM119.34,241.18c1.2,0 2.21,-0.41 3.03,-1.23 0.82,-0.82 1.23,-1.83 1.23,-3.03 -0,-1.2 -0.41,-2.21 -1.23,-3.03 -0.82,-0.82 -1.83,-1.23 -3.03,-1.23 -1.2,0 -2.21,0.41 -3.03,1.23 -0.82,0.82 -1.23,1.83 -1.23,3.03s0.41,2.21 1.23,3.03c0.82,0.82 1.83,1.23 3.03,1.23ZM119.34,248.55l3.41,-3.38h4.77v-4.77l3.44,-3.44 -3.44,-3.44v-4.77h-4.77l-3.41,-3.44 -3.48,3.44h-4.77v4.77l-3.44,3.44 3.44,3.44v4.77h4.74l3.51,3.38Z"
android:fillColor="#fff"/>
<path
- android:pathData="M207.03,180.82h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M207.39,212.99h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#de9834"/>
<path
- android:pathData="M207.05,209.09l-3.16,-3.06h-4.35v-4.35l-3.13,-3.13 3.13,-3.13v-4.35h4.35l3.16,-3.13 3.11,3.13h4.35v4.35l3.13,3.13 -3.13,3.13v4.35h-4.35l-3.11,3.06ZM207.05,203.08c1.26,0 2.34,-0.44 3.23,-1.33 0.89,-0.89 1.33,-1.96 1.33,-3.23s-0.44,-2.34 -1.33,-3.23c-0.89,-0.89 -1.96,-1.33 -3.23,-1.33 -1.26,0 -2.34,0.44 -3.23,1.33 -0.89,0.89 -1.33,1.96 -1.33,3.23s0.44,2.34 1.33,3.23c0.89,0.89 1.96,1.33 3.23,1.33ZM207.05,201.68c0.89,0 1.64,-0.3 2.24,-0.91 0.61,-0.61 0.91,-1.36 0.91,-2.24 -0,-0.89 -0.3,-1.64 -0.91,-2.24 -0.61,-0.61 -1.36,-0.91 -2.24,-0.91 -0.89,0 -1.64,0.3 -2.24,0.91 -0.61,0.61 -0.91,1.36 -0.91,2.24s0.3,1.64 0.91,2.24c0.61,0.61 1.36,0.91 2.24,0.91ZM207.05,207.13l2.53,-2.5h3.53v-3.53l2.55,-2.55 -2.55,-2.55v-3.53h-3.53l-2.53,-2.55 -2.57,2.55h-3.53v3.53l-2.55,2.55 2.55,2.55v3.53h3.51l2.6,2.5ZM207.05,201.68c0.89,0 1.64,-0.3 2.24,-0.91 0.61,-0.61 0.91,-1.36 0.91,-2.24 -0,-0.89 -0.3,-1.64 -0.91,-2.24 -0.61,-0.61 -1.36,-0.91 -2.24,-0.91 -0.89,0 -1.64,0.3 -2.24,0.91 -0.61,0.61 -0.91,1.36 -0.91,2.24s0.3,1.64 0.91,2.24c0.61,0.61 1.36,0.91 2.24,0.91Z"
+ android:pathData="M207.42,251.21l-4.27,-4.14h-5.88v-5.88l-4.23,-4.23 4.23,-4.23v-5.88h5.88l4.27,-4.23 4.2,4.23h5.88v5.88l4.23,4.23 -4.23,4.23v5.88h-5.88l-4.2,4.14ZM207.42,243.09c1.71,0 3.16,-0.6 4.36,-1.8 1.2,-1.2 1.8,-2.65 1.8,-4.36s-0.6,-3.16 -1.8,-4.36c-1.2,-1.2 -2.65,-1.8 -4.36,-1.8 -1.71,0 -3.16,0.6 -4.36,1.8 -1.2,1.2 -1.8,2.65 -1.8,4.36s0.6,3.16 1.8,4.36c1.2,1.2 2.65,1.8 4.36,1.8ZM207.42,241.19c1.2,0 2.21,-0.41 3.03,-1.23 0.82,-0.82 1.23,-1.83 1.23,-3.03 -0,-1.2 -0.41,-2.21 -1.23,-3.03 -0.82,-0.82 -1.83,-1.23 -3.03,-1.23 -1.2,0 -2.21,0.41 -3.03,1.23 -0.82,0.82 -1.23,1.83 -1.23,3.03s0.41,2.21 1.23,3.03c0.82,0.82 1.83,1.23 3.03,1.23ZM207.42,248.55l3.41,-3.38h4.77v-4.77l3.44,-3.44 -3.44,-3.44v-4.77h-4.77l-3.41,-3.44 -3.48,3.44h-4.77v4.77l-3.44,3.44 3.44,3.44v4.77h4.74l3.51,3.38ZM207.42,241.19c1.2,0 2.21,-0.41 3.03,-1.23 0.82,-0.82 1.23,-1.83 1.23,-3.03 -0,-1.2 -0.41,-2.21 -1.23,-3.03 -0.82,-0.82 -1.83,-1.23 -3.03,-1.23 -1.2,0 -2.21,0.41 -3.03,1.23 -0.82,0.82 -1.23,1.83 -1.23,3.03s0.41,2.21 1.23,3.03c0.82,0.82 1.83,1.23 3.03,1.23Z"
android:fillColor="#fff"/>
<path
- android:pathData="M270.14,180.81h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M292.7,212.98h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#438947"/>
<path
- android:pathData="M263.92,207.44c-0.4,0 -0.74,-0.14 -1.02,-0.42s-0.42,-0.62 -0.42,-1.02v-10.37c0,-0.4 0.14,-0.74 0.42,-1.02s0.62,-0.42 1.02,-0.42h1.67v-2.29c0,-1.26 0.44,-2.33 1.33,-3.22 0.88,-0.88 1.96,-1.33 3.22,-1.33s2.33,0.44 3.22,1.33c0.88,0.88 1.33,1.96 1.33,3.22v2.29h1.67c0.4,0 0.74,0.14 1.02,0.42s0.42,0.62 0.42,1.02v10.37c0,0.4 -0.14,0.74 -0.42,1.02s-0.62,0.42 -1.02,0.42h-12.43ZM263.92,206.01h12.43v-10.37h-12.43v10.37ZM270.14,202.66c0.51,0 0.94,-0.18 1.3,-0.53s0.54,-0.77 0.54,-1.27c0,-0.48 -0.18,-0.91 -0.54,-1.3s-0.79,-0.59 -1.3,-0.59 -0.94,0.2 -1.3,0.59c-0.36,0.39 -0.54,0.82 -0.54,1.3 0,0.49 0.18,0.92 0.54,1.27s0.79,0.53 1.3,0.53ZM267.03,194.2h6.22v-2.29c0,-0.86 -0.3,-1.59 -0.91,-2.2 -0.61,-0.61 -1.34,-0.91 -2.2,-0.91s-1.59,0.3 -2.2,0.91 -0.91,1.34 -0.91,2.2v2.29ZM263.92,206.01v0Z"
+ android:pathData="M284.29,248.97c-0.54,0 -1,-0.19 -1.37,-0.57s-0.57,-0.83 -0.57,-1.37v-14.02c0,-0.54 0.19,-1 0.57,-1.37s0.83,-0.57 1.37,-0.57h2.26v-3.1c0,-1.7 0.6,-3.15 1.79,-4.35 1.2,-1.2 2.64,-1.79 4.35,-1.79s3.15,0.6 4.35,1.79c1.2,1.2 1.79,2.64 1.79,4.35v3.1h2.26c0.54,0 1,0.19 1.37,0.57s0.57,0.83 0.57,1.37v14.02c0,0.54 -0.19,1 -0.57,1.37s-0.83,0.57 -1.37,0.57h-16.8ZM284.29,247.03h16.8v-14.02h-16.8v14.02ZM292.7,242.51c0.69,0 1.28,-0.24 1.76,-0.71s0.73,-1.04 0.73,-1.71c0,-0.65 -0.24,-1.23 -0.73,-1.76s-1.07,-0.79 -1.76,-0.79 -1.28,0.26 -1.76,0.79c-0.48,0.53 -0.73,1.11 -0.73,1.76 0,0.67 0.24,1.24 0.73,1.71s1.07,0.71 1.76,0.71ZM288.5,231.07h8.4v-3.1c0,-1.16 -0.41,-2.15 -1.23,-2.97 -0.82,-0.82 -1.81,-1.23 -2.97,-1.23s-2.15,0.41 -2.97,1.23 -1.23,1.81 -1.23,2.97v3.1ZM284.29,247.03v0Z"
android:fillColor="#fff"/>
<path
- android:pathData="M207.03,116.5h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M207.39,126.06h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#327969"/>
<path
- android:pathData="M209.17,143.6v-1.66c1.73,-0.5 3.15,-1.46 4.25,-2.88 1.1,-1.42 1.65,-3.03 1.65,-4.84 0,-1.8 -0.54,-3.42 -1.63,-4.85s-2.51,-2.38 -4.26,-2.87v-1.66c2.22,0.5 4.02,1.62 5.41,3.36 1.39,1.74 2.09,3.75 2.09,6.02s-0.7,4.27 -2.09,6.02c-1.39,1.74 -3.2,2.86 -5.41,3.36ZM197.38,137.46v-6.43h4.29l5.36,-5.36v17.15l-5.36,-5.36h-4.29ZM208.63,138.75v-9.03c0.98,0.3 1.76,0.88 2.34,1.71 0.58,0.84 0.87,1.78 0.87,2.81 0,1.02 -0.29,1.95 -0.88,2.79s-1.37,1.41 -2.33,1.71ZM205.42,129.75l-3.03,2.89h-3.4v3.22h3.4l3.03,2.92v-9.03Z"
+ android:pathData="M210.29,162.68v-2.25c2.34,-0.68 4.26,-1.97 5.74,-3.89 1.49,-1.92 2.23,-4.1 2.23,-6.54 0,-2.44 -0.74,-4.62 -2.21,-6.56 -1.47,-1.93 -3.39,-3.22 -5.76,-3.88v-2.25c2.99,0.68 5.43,2.19 7.32,4.55 1.88,2.35 2.83,5.06 2.83,8.13s-0.94,5.78 -2.83,8.13c-1.88,2.35 -4.32,3.87 -7.32,4.55ZM194.35,154.39v-8.69h5.8l7.24,-7.24v23.18l-7.24,-7.24h-5.8ZM209.56,156.13v-12.21c1.33,0.41 2.38,1.18 3.17,2.32 0.78,1.13 1.18,2.4 1.18,3.8 0,1.38 -0.4,2.63 -1.2,3.77s-1.85,1.91 -3.15,2.32ZM205.21,143.96l-4.09,3.91h-4.6v4.35h4.6l4.09,3.95v-12.21Z"
android:fillColor="#fff"/>
<path
- android:pathData="M270.14,116.54h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M292.7,126.1h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#9f3ebf"/>
<path
- android:pathData="M275.08,127.12h-9.89v14.23h9.89v-14.23Z"
+ android:pathData="M299.38,140.4h-13.36v19.23h13.36v-19.23Z"
android:fillColor="#fff"/>
<path
- android:pathData="M263.88,129.91h-3.56v8.76h3.56v-8.76Z"
+ android:pathData="M284.23,144.18h-4.81v11.84h4.81v-11.84Z"
android:fillColor="#fff"/>
<path
- android:pathData="M279.96,129.91h-3.56v8.76h3.56v-8.76Z"
+ android:pathData="M305.97,144.18h-4.81v11.84h4.81v-11.84Z"
android:fillColor="#fff"/>
<path
- android:pathData="M267.04,128.82h6.21v10.83h-6.21z"
+ android:pathData="M288.5,142.7h8.39v14.63h-8.39z"
android:fillColor="#9f3ebf"/>
<path
- android:pathData="M141.86,116.5h0c9.77,0 17.7,7.92 17.7,17.7h0c0,9.77 -7.92,17.7 -17.7,17.7h0c-9.77,0 -17.7,-7.92 -17.7,-17.7h0c0,-9.77 7.92,-17.7 17.7,-17.7Z"
+ android:pathData="M119.3,126.06h0c13.21,0 23.92,10.71 23.92,23.92h0c0,13.21 -10.71,23.92 -23.92,23.92h0c-13.21,0 -23.92,-10.71 -23.92,-23.92h0c0,-13.21 10.71,-23.92 23.92,-23.92Z"
android:fillColor="#327969"/>
<path
- android:pathData="M134.62,137.44v-6.43h4.29l5.36,-5.36v17.16l-5.36,-5.36h-4.29ZM145.88,138.73v-9.03c0.97,0.3 1.74,0.88 2.33,1.72 0.59,0.84 0.88,1.78 0.88,2.81 0,1.05 -0.29,1.99 -0.88,2.81s-1.37,1.39 -2.33,1.69ZM142.66,129.72l-3.03,2.9h-3.4v3.22h3.4l3.03,2.92v-9.03Z"
+ android:pathData="M109.52,154.35v-8.7h5.8l7.25,-7.25v23.19l-7.25,-7.25h-5.8ZM124.74,156.09v-12.21c1.3,0.41 2.36,1.18 3.15,2.32 0.8,1.14 1.2,2.4 1.2,3.8 0,1.43 -0.4,2.69 -1.2,3.8s-1.85,1.87 -3.15,2.28ZM120.39,143.92l-4.09,3.91h-4.6v4.35h4.6l4.09,3.95v-12.21Z"
android:fillColor="#fff"/>
<path
- android:pathData="M141.86,81.15l-2.93,-2.93h-4.39c-0.39,0 -0.73,-0.15 -1.02,-0.44 -0.29,-0.29 -0.44,-0.63 -0.44,-1.02v-14.63c0,-0.39 0.15,-0.73 0.44,-1.02 0.29,-0.29 0.63,-0.44 1.02,-0.44h14.63c0.39,0 0.73,0.15 1.02,0.44 0.29,0.29 0.44,0.63 0.44,1.02v14.63c0,0.39 -0.15,0.73 -0.44,1.02 -0.29,0.29 -0.63,0.44 -1.02,0.44h-4.39l-2.93,2.93ZM141.88,74l1.37,-3.12 3.12,-1.37 -3.12,-1.37 -1.37,-3.12 -1.39,3.12 -3.1,1.37 3.1,1.37 1.39,3.12Z"
+ android:pathData="M119.09,78.27l-3.9,-4.01 -5.93,-0.08c-0.53,-0.01 -0.99,-0.21 -1.38,-0.61 -0.39,-0.4 -0.58,-0.86 -0.57,-1.39l0.26,-19.77c0.01,-0.53 0.21,-0.99 0.61,-1.38 0.4,-0.39 0.86,-0.58 1.39,-0.57l19.77,0.26c0.53,0.01 0.99,0.21 1.38,0.61 0.39,0.4 0.58,0.86 0.57,1.39l-0.26,19.77c-0.01,0.53 -0.21,0.99 -0.61,1.38 -0.4,0.39 -0.86,0.58 -1.39,0.57l-5.93,-0.08 -4.01,3.9ZM119.25,68.61l1.9,-4.19 4.24,-1.79 -4.19,-1.9 -1.79,-4.24 -1.93,4.19 -4.21,1.79 4.16,1.9 1.82,4.24Z"
android:fillColor="#fff"/>
</vector>
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
index 26eefa9..5212e8e 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/dynamiccolor/MaterialDynamicColors.java
@@ -17,15 +17,18 @@
package com.android.systemui.monet.dynamiccolor;
import com.android.systemui.monet.dislike.DislikeAnalyzer;
-import com.android.systemui.monet.dynamiccolor.DynamicColor;
-import com.android.systemui.monet.dynamiccolor.ToneDeltaConstraint;
-import com.android.systemui.monet.dynamiccolor.TonePolarity;
import com.android.systemui.monet.hct.Hct;
import com.android.systemui.monet.hct.ViewingConditions;
import com.android.systemui.monet.scheme.DynamicScheme;
import com.android.systemui.monet.scheme.Variant;
/** Named colors, otherwise known as tokens, or roles, in the Material Design system. */
+// Prevent lint for Function.apply not being available on Android before API level 14 (4.0.1).
+// "AndroidJdkLibsChecker" for Function, "NewApi" for Function.apply().
+// A java_library Bazel rule with an Android constraint cannot skip these warnings without this
+// annotation; another solution would be to create an android_library rule and supply
+// AndroidManifest with an SDK set higher than 14.
+@SuppressWarnings({"AndroidJdkLibsChecker", "NewApi"})
public final class MaterialDynamicColors {
private static final double CONTAINER_ACCENT_TONE_DELTA = 15.0;
@@ -33,7 +36,6 @@
private MaterialDynamicColors() {
}
- /** In light mode, the darkest surface. In dark mode, the lightest surface. */
public static DynamicColor highestSurface(DynamicScheme s) {
return s.isDark ? surfaceBright : surfaceDim;
}
@@ -49,7 +51,7 @@
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 98.0);
public static final DynamicColor surfaceInverse =
- DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 20.0);
+ DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 90.0 : 30.0);
public static final DynamicColor surfaceBright =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 24.0 : 98.0);
@@ -57,19 +59,19 @@
public static final DynamicColor surfaceDim =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 6.0 : 87.0);
- public static final DynamicColor surfaceContainerLowest =
+ public static final DynamicColor surfaceSub2 =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 4.0 : 100.0);
- public static final DynamicColor surfaceContainerLow =
+ public static final DynamicColor surfaceSub1 =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 96.0);
public static final DynamicColor surfaceContainer =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 12.0 : 94.0);
- public static final DynamicColor surfaceContainerHigh =
+ public static final DynamicColor surfaceAdd1 =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 17.0 : 92.0);
- public static final DynamicColor surfaceContainerHighest =
+ public static final DynamicColor surfaceAdd2 =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 22.0 : 90.0);
public static final DynamicColor onSurface =
@@ -95,7 +97,8 @@
public static final DynamicColor outlineVariant =
DynamicColor.fromPalette(
- (s) -> s.neutralVariantPalette, (s) -> 80.0, (s) -> highestSurface(s));
+ (s) -> s.neutralVariantPalette, (s) -> s.isDark ? 30.0 : 80.0,
+ (s) -> highestSurface(s));
public static final DynamicColor primaryContainer =
DynamicColor.fromPalette(
@@ -115,7 +118,7 @@
if (!isFidelity(s)) {
return s.isDark ? 90.0 : 10.0;
}
- return DynamicColor.contrastingTone(primaryContainer.getTone(s), 4.5);
+ return DynamicColor.contrastingTone(primaryContainer.tone.apply(s), 4.5);
},
(s) -> primaryContainer,
null);
@@ -165,7 +168,7 @@
if (!isFidelity(s)) {
return s.isDark ? 90.0 : 10.0;
}
- return DynamicColor.contrastingTone(secondaryContainer.getTone(s), 4.5);
+ return DynamicColor.contrastingTone(secondaryContainer.tone.apply(s), 4.5);
},
(s) -> secondaryContainer);
@@ -206,7 +209,7 @@
if (!isFidelity(s)) {
return s.isDark ? 90.0 : 10.0;
}
- return DynamicColor.contrastingTone(tertiaryContainer.getTone(s), 4.5);
+ return DynamicColor.contrastingTone(tertiaryContainer.tone.apply(s), 4.5);
},
(s) -> tertiaryContainer);
@@ -252,49 +255,49 @@
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor primaryFixedDim =
+ public static final DynamicColor primaryFixedDarker =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onPrimaryFixed =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 10.0,
- (s) -> primaryFixedDim);
+ (s) -> primaryFixedDarker);
public static final DynamicColor onPrimaryFixedVariant =
DynamicColor.fromPalette((s) -> s.primaryPalette, (s) -> 30.0,
- (s) -> primaryFixedDim);
+ (s) -> primaryFixedDarker);
public static final DynamicColor secondaryFixed =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor secondaryFixedDim =
+ public static final DynamicColor secondaryFixedDarker =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onSecondaryFixed =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 10.0,
- (s) -> secondaryFixedDim);
+ (s) -> secondaryFixedDarker);
public static final DynamicColor onSecondaryFixedVariant =
DynamicColor.fromPalette((s) -> s.secondaryPalette, (s) -> 30.0,
- (s) -> secondaryFixedDim);
+ (s) -> secondaryFixedDarker);
public static final DynamicColor tertiaryFixed =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 90.0,
(s) -> highestSurface(s));
- public static final DynamicColor tertiaryFixedDim =
+ public static final DynamicColor tertiaryFixedDarker =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 80.0,
(s) -> highestSurface(s));
public static final DynamicColor onTertiaryFixed =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 10.0,
- (s) -> tertiaryFixedDim);
+ (s) -> tertiaryFixedDarker);
public static final DynamicColor onTertiaryFixedVariant =
DynamicColor.fromPalette((s) -> s.tertiaryPalette, (s) -> 30.0,
- (s) -> tertiaryFixedDim);
+ (s) -> tertiaryFixedDarker);
/**
* These colors were present in Android framework before Android U, and used by MDC controls.
@@ -366,27 +369,6 @@
public static final DynamicColor textHintInverse =
DynamicColor.fromPalette((s) -> s.neutralPalette, (s) -> s.isDark ? 10.0 : 90.0);
- public static final DynamicColor primaryPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.primaryPalette, (s) -> s.primaryPalette.getKeyColor().getTone());
-
- public static final DynamicColor secondaryPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.secondaryPalette, (s) -> s.secondaryPalette.getKeyColor().getTone());
-
- public static final DynamicColor tertiaryPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.tertiaryPalette, (s) -> s.tertiaryPalette.getKeyColor().getTone());
-
- public static final DynamicColor neutralPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.neutralPalette, (s) -> s.neutralPalette.getKeyColor().getTone());
-
- public static final DynamicColor neutralVariantPaletteKeyColor =
- DynamicColor.fromPalette(
- (s) -> s.neutralVariantPalette,
- (s) -> s.neutralVariantPalette.getKeyColor().getTone());
-
private static ViewingConditions viewingConditionsForAlbers(DynamicScheme scheme) {
return ViewingConditions.defaultWithBackgroundLstar(scheme.isDark ? 30.0 : 80.0);
}
@@ -433,4 +415,35 @@
return DynamicColor.enableLightForeground(albersd.getTone());
}
}
+
+ // Compatibility mappings for Android
+ public static final DynamicColor surfaceContainerLow = surfaceSub1;
+ public static final DynamicColor surfaceContainerLowest = surfaceSub2;
+ public static final DynamicColor surfaceContainerHigh = surfaceAdd1;
+ public static final DynamicColor surfaceContainerHighest = surfaceAdd2;
+ public static final DynamicColor primaryFixedDim = primaryFixedDarker;
+ public static final DynamicColor secondaryFixedDim = secondaryFixedDarker;
+ public static final DynamicColor tertiaryFixedDim = tertiaryFixedDarker;
+
+ // Compatibility Keys Colors for Android
+ public static final DynamicColor primaryPaletteKeyColor =
+ DynamicColor.fromPalette(
+ (s) -> s.primaryPalette, (s) -> s.primaryPalette.getKeyColor().getTone());
+
+ public static final DynamicColor secondaryPaletteKeyColor =
+ DynamicColor.fromPalette(
+ (s) -> s.secondaryPalette, (s) -> s.secondaryPalette.getKeyColor().getTone());
+
+ public static final DynamicColor tertiaryPaletteKeyColor =
+ DynamicColor.fromPalette(
+ (s) -> s.tertiaryPalette, (s) -> s.tertiaryPalette.getKeyColor().getTone());
+
+ public static final DynamicColor neutralPaletteKeyColor =
+ DynamicColor.fromPalette(
+ (s) -> s.neutralPalette, (s) -> s.neutralPalette.getKeyColor().getTone());
+
+ public static final DynamicColor neutralVariantPaletteKeyColor =
+ DynamicColor.fromPalette(
+ (s) -> s.neutralVariantPalette,
+ (s) -> s.neutralVariantPalette.getKeyColor().getTone());
}
diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml
index df65336..fb7aa72 100644
--- a/packages/SystemUI/res-product/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml
@@ -40,9 +40,9 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
- <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
- <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
- <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the tablet."</string>
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the device."</string>
+ <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the phone."</string>
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string>
diff --git a/packages/SystemUI/res/drawable/control_spinner_background.xml b/packages/SystemUI/res/drawable/control_spinner_background.xml
index 46a9dad..8416f9d 100644
--- a/packages/SystemUI/res/drawable/control_spinner_background.xml
+++ b/packages/SystemUI/res/drawable/control_spinner_background.xml
@@ -23,7 +23,7 @@
<item
android:drawable="@drawable/ic_ksh_key_down"
android:gravity="end|bottom"
- android:paddingBottom="6dp"
+ android:bottom="4dp"
android:width="24dp"
android:height="24dp"
android:end="12dp" />
diff --git a/packages/SystemUI/res/drawable/controls_popup_bg.xml b/packages/SystemUI/res/drawable/controls_popup_bg.xml
new file mode 100644
index 0000000..34dd6e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/controls_popup_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/transparent" />
+ <corners android:radius="@dimen/control_popup_corner_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/controls_popup_item_background.xml b/packages/SystemUI/res/drawable/controls_popup_item_background.xml
new file mode 100644
index 0000000..7992180
--- /dev/null
+++ b/packages/SystemUI/res/drawable/controls_popup_item_background.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/control_popup_item_corner_radius" />
+ <solid android:color="#303030" />
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/control_popup_item_corner_radius" />
+ <solid android:color="#1f1f1f" />
+ </shape>
+ </item>
+</selector>
diff --git a/packages/SystemUI/res/layout/controls_spinner_item.xml b/packages/SystemUI/res/layout/controls_spinner_item.xml
index 574aed6..4048d03 100644
--- a/packages/SystemUI/res/layout/controls_spinner_item.xml
+++ b/packages/SystemUI/res/layout/controls_spinner_item.xml
@@ -13,33 +13,28 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingVertical="@dimen/control_spinner_padding_vertical"
- android:paddingHorizontal="@dimen/control_spinner_padding_horizontal">
+ android:layout_height="@dimen/control_popup_item_height"
+ android:background="@drawable/controls_popup_item_background"
+ android:gravity="center_vertical|start"
+ android:orientation="horizontal"
+ android:paddingStart="@dimen/control_popup_item_padding"
+ android:paddingEnd="@dimen/control_popup_item_padding">
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_width="@dimen/controls_header_app_icon_size"
+ android:layout_height="@dimen/controls_header_app_icon_size"
+ android:layout_marginEnd="@dimen/control_popup_item_padding"
+ android:contentDescription="@null"
+ tools:src="@drawable/ic_android" />
+
+ <TextView
+ android:id="@+id/controls_spinner_item"
+ style="@style/Control.Spinner.Item"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center">
-
- <ImageView
- android:id="@+id/app_icon"
- android:layout_gravity="center"
- android:layout_width="@dimen/controls_header_app_icon_size"
- android:layout_height="@dimen/controls_header_app_icon_size"
- android:contentDescription="@null"
- android:layout_marginEnd="10dp" />
-
- <TextView
- style="@style/Control.Spinner.Item"
- android:id="@+id/controls_spinner_item"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
- </LinearLayout>
-
+ tools:text="Android" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml
index 71561c0..b1259e4 100644
--- a/packages/SystemUI/res/layout/controls_with_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_with_favorites.xml
@@ -50,11 +50,9 @@
<LinearLayout
android:id="@+id/controls_header"
android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
- android:minHeight="48dp"
android:orientation="horizontal">
<TextView
@@ -64,7 +62,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="false"
- tools:text="Test app" />
+ tools:text="@tools:sample/lorem" />
</LinearLayout>
<ImageView
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
index efcb6f3..8bff1a1 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -29,9 +29,10 @@
android:format12Hour="@string/dream_time_complication_12_hr_time_format"
android:format24Hour="@string/dream_time_complication_24_hr_time_format"
android:fontFeatureSettings="pnum, lnum"
+ android:includeFontPadding="false"
android:letterSpacing="0.02"
+ android:maxLines="1"
android:textSize="@dimen/dream_overlay_complication_clock_time_text_size"
- android:translationY="@dimen/dream_overlay_complication_clock_time_translation_y"
app:keyShadowBlur="@dimen/dream_overlay_clock_key_text_shadow_radius"
app:keyShadowOffsetX="@dimen/dream_overlay_clock_key_text_shadow_dx"
app:keyShadowOffsetY="@dimen/dream_overlay_clock_key_text_shadow_dy"
@@ -40,6 +41,7 @@
app:ambientShadowOffsetX="@dimen/dream_overlay_clock_ambient_text_shadow_dx"
app:ambientShadowOffsetY="@dimen/dream_overlay_clock_ambient_text_shadow_dy"
app:ambientShadowAlpha="0.3"
- />
+ app:removeTextDescent="true"
+ app:textDescentExtraPadding="@dimen/dream_overlay_clock_text_descent_extra_padding" />
</FrameLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 31071ca..0d638f6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -206,6 +206,7 @@
<color name="control_thumbnail_tint">#33000000</color>
<color name="control_thumbnail_shadow_color">@*android:color/black</color>
<color name="controls_task_view_bg">#CC191C1D</color>
+ <color name="control_popup_dim">#8A000000</color>
<!-- Keyboard backlight indicator-->
<color name="backlight_indicator_step_filled">#F6E388</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a52a2b7..3ab654f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1200,6 +1200,13 @@
<dimen name="control_menu_item_min_height">56dp</dimen>
<dimen name="control_menu_vertical_padding">12dp</dimen>
<dimen name="control_menu_horizontal_padding">16dp</dimen>
+ <dimen name="control_popup_item_corner_radius">4dp</dimen>
+ <dimen name="control_popup_item_height">56dp</dimen>
+ <dimen name="control_popup_item_padding">16dp</dimen>
+ <dimen name="control_popup_items_divider_height">1dp</dimen>
+ <dimen name="control_popup_max_width">380dp</dimen>
+ <dimen name="control_popup_corner_radius">28dp</dimen>
+ <dimen name="control_popup_horizontal_margin">16dp</dimen>
<dimen name="control_spinner_padding_vertical">24dp</dimen>
<dimen name="control_spinner_padding_horizontal">20dp</dimen>
<dimen name="control_text_size">14sp</dimen>
@@ -1629,7 +1636,6 @@
<dimen name="dream_overlay_bottom_affordance_radius">32dp</dimen>
<dimen name="dream_overlay_bottom_affordance_padding">14dp</dimen>
<dimen name="dream_overlay_complication_clock_time_text_size">86dp</dimen>
- <dimen name="dream_overlay_complication_clock_time_translation_y">28dp</dimen>
<dimen name="dream_overlay_complication_clock_subtitle_text_size">24sp</dimen>
<dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
<dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
@@ -1730,6 +1736,7 @@
<dimen name="dream_overlay_clock_ambient_text_shadow_dx">0dp</dimen>
<dimen name="dream_overlay_clock_ambient_text_shadow_dy">0dp</dimen>
<dimen name="dream_overlay_clock_ambient_text_shadow_radius">1dp</dimen>
+ <dimen name="dream_overlay_clock_text_descent_extra_padding">1dp</dimen>
<!-- Shadow for dream overlay status bar complications -->
<dimen name="dream_overlay_status_bar_key_text_shadow_dx">0.5dp</dimen>
diff --git a/packages/SystemUI/shared/res/values/attrs.xml b/packages/SystemUI/shared/res/values/attrs.xml
index f3aeaef..84ea6b7 100644
--- a/packages/SystemUI/shared/res/values/attrs.xml
+++ b/packages/SystemUI/shared/res/values/attrs.xml
@@ -40,6 +40,9 @@
<attr name="ambientShadowOffsetX" />
<attr name="ambientShadowOffsetY" />
<attr name="ambientShadowAlpha" />
+ <attr name="removeTextDescent" format="boolean" />
+ <!-- padding to add back when removing text descent so it ensures text is not clipped -->
+ <attr name="textDescentExtraPadding" format="dimension" />
</declare-styleable>
<declare-styleable name="DoubleShadowTextView">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt
index f2db129..5a6f184 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowTextClock.kt
@@ -22,6 +22,7 @@
import com.android.systemui.shared.R
import com.android.systemui.shared.shadow.DoubleShadowTextHelper.ShadowInfo
import com.android.systemui.shared.shadow.DoubleShadowTextHelper.applyShadows
+import kotlin.math.floor
/** Extension of [TextClock] which draws two shadows on the text (ambient and key shadows) */
class DoubleShadowTextClock
@@ -89,6 +90,21 @@
ambientShadowOffsetY.toFloat(),
ambientShadowAlpha
)
+ val removeTextDescent =
+ attributes.getBoolean(R.styleable.DoubleShadowTextClock_removeTextDescent, false)
+ val textDescentExtraPadding =
+ attributes.getDimensionPixelSize(
+ R.styleable.DoubleShadowTextClock_textDescentExtraPadding,
+ 0
+ )
+ if (removeTextDescent) {
+ setPaddingRelative(
+ 0,
+ 0,
+ 0,
+ textDescentExtraPadding - floor(paint.fontMetrics.descent.toDouble()).toInt()
+ )
+ }
} finally {
attributes.recycle()
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 1351314..6c59a94 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -122,6 +122,8 @@
// Whether the screen is currently transitioning into the state indicated by
// SYSUI_STATE_SCREEN_ON.
public static final int SYSUI_STATE_SCREEN_TRANSITION = 1 << 29;
+ // The notification panel expansion fraction is > 0
+ public static final int SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE = 1 << 30;
// Mask for SystemUiStateFlags to isolate SYSUI_STATE_SCREEN_ON and
// SYSUI_STATE_SCREEN_TRANSITION, to match SCREEN_STATE_*
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index e7ec3eb..cbc0a1b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -60,6 +60,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.internal.util.LatencyTracker;
@@ -171,6 +172,7 @@
@NonNull private final SecureSettings mSecureSettings;
@NonNull private final UdfpsUtils mUdfpsUtils;
@NonNull private final InputManager mInputManager;
+ private final boolean mIgnoreRefreshRate;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@@ -816,6 +818,8 @@
mExecution = execution;
mVibrator = vibrator;
mInflater = inflater;
+ mIgnoreRefreshRate = mContext.getResources()
+ .getBoolean(R.bool.config_ignoreUdfpsVote);
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
// fingerprint manager should never be null.
mFingerprintManager = checkNotNull(fingerprintManager);
@@ -1069,6 +1073,18 @@
return mOnFingerDown;
}
+ private void dispatchOnUiReady(long requestId) {
+ if (mAlternateTouchProvider != null) {
+ mBiometricExecutor.execute(() -> {
+ mAlternateTouchProvider.onUiReady();
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+ });
+ } else {
+ mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId);
+ mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
+ }
+ }
+
private void onFingerDown(
long requestId,
int x,
@@ -1146,17 +1162,11 @@
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
final UdfpsView view = mOverlay.getOverlayView();
if (view != null && isOptical()) {
- view.configureDisplay(() -> {
- if (mAlternateTouchProvider != null) {
- mBiometricExecutor.execute(() -> {
- mAlternateTouchProvider.onUiReady();
- mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
- });
- } else {
- mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId);
- mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
- }
- });
+ if (mIgnoreRefreshRate) {
+ dispatchOnUiReady(requestId);
+ } else {
+ view.configureDisplay(() -> dispatchOnUiReady(requestId));
+ }
}
for (Callback cb : mCallbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
index 6615f6b..f9613d50 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
@@ -109,7 +109,7 @@
@AnyThread
fun closeSystemDialogs() {
sendInBackground {
- context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ context.closeSystemDialogs()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index f83885b..d6c85fb 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -16,6 +16,8 @@
package com.android.systemui.classifier;
+import static com.android.systemui.classifier.FalsingModule.IS_FOLDABLE_DEVICE;
+
import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
@@ -30,6 +32,7 @@
import java.util.List;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* Acts as a cache and utility class for FalsingClassifiers.
@@ -46,6 +49,7 @@
private BatteryController mBatteryController;
private final FoldStateListener mFoldStateListener;
private final DockManager mDockManager;
+ private boolean mIsFoldableDevice;
private final float mXdpi;
private final float mYdpi;
private final List<SessionListener> mSessionListeners = new ArrayList<>();
@@ -70,7 +74,8 @@
DisplayMetrics displayMetrics,
BatteryController batteryController,
FoldStateListener foldStateListener,
- DockManager dockManager) {
+ DockManager dockManager,
+ @Named(IS_FOLDABLE_DEVICE) boolean isFoldableDevice) {
mXdpi = displayMetrics.xdpi;
mYdpi = displayMetrics.ydpi;
mWidthPixels = displayMetrics.widthPixels;
@@ -78,6 +83,7 @@
mBatteryController = batteryController;
mFoldStateListener = foldStateListener;
mDockManager = dockManager;
+ mIsFoldableDevice = isFoldableDevice;
FalsingClassifier.logInfo("xdpi, ydpi: " + getXdpi() + ", " + getYdpi());
FalsingClassifier.logInfo("width, height: " + getWidthPixels() + ", " + getHeightPixels());
@@ -417,7 +423,7 @@
}
public boolean isUnfolded() {
- return Boolean.FALSE.equals(mFoldStateListener.getFolded());
+ return mIsFoldableDevice && Boolean.FALSE.equals(mFoldStateListener.getFolded());
}
/** Implement to be alerted abotu the beginning and ending of falsing tracking. */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
index 5302af9..c7f3b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
@@ -43,6 +43,7 @@
String LONG_TAP_TOUCH_SLOP = "falsing_long_tap_slop";
String DOUBLE_TAP_TOUCH_SLOP = "falsing_double_tap_touch_slop";
String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms";
+ String IS_FOLDABLE_DEVICE = "falsing_foldable_device";
/** */
@Binds
@@ -89,4 +90,16 @@
static float providesLongTapTouchSlop(ViewConfiguration viewConfiguration) {
return viewConfiguration.getScaledTouchSlop() * 1.25f;
}
+
+ /** */
+ @Provides
+ @Named(IS_FOLDABLE_DEVICE)
+ static boolean providesIsFoldableDevice(@Main Resources resources) {
+ try {
+ return resources.getIntArray(
+ com.android.internal.R.array.config_foldedDeviceStates).length != 0;
+ } catch (Resources.NotFoundException e) {
+ return false;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsPopupMenu.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsPopupMenu.kt
new file mode 100644
index 0000000..d08bc48e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsPopupMenu.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.view.Gravity
+import android.view.View
+import android.widget.ListPopupWindow
+import android.widget.PopupWindow
+import com.android.systemui.R
+
+class ControlsPopupMenu(context: Context) : ListPopupWindow(context) {
+
+ private val resources: Resources = context.resources
+
+ private val listDividerHeight: Int =
+ resources.getDimensionPixelSize(R.dimen.control_popup_items_divider_height)
+ private val horizontalMargin: Int =
+ resources.getDimensionPixelSize(R.dimen.control_popup_horizontal_margin)
+ private val maxWidth: Int = resources.getDimensionPixelSize(R.dimen.control_popup_max_width)
+
+ private val dialogBackground: Drawable = resources.getDrawable(R.drawable.controls_popup_bg)!!
+ private val dimDrawable: Drawable = ColorDrawable(resources.getColor(R.color.control_popup_dim))
+
+ private var dismissListener: PopupWindow.OnDismissListener? = null
+
+ init {
+ setBackgroundDrawable(dialogBackground)
+
+ inputMethodMode = INPUT_METHOD_NOT_NEEDED
+ isModal = true
+ setDropDownGravity(Gravity.START)
+
+ // dismiss method isn't called when popup is hidden by outside touch. So we need to
+ // override a listener to remove a dimming foreground
+ super.setOnDismissListener {
+ anchorView?.rootView?.foreground = null
+ dismissListener?.onDismiss()
+ }
+ }
+
+ override fun show() {
+ // need to call show() first in order to construct the listView
+ super.show()
+
+ val paddedWidth = resources.displayMetrics.widthPixels - 2 * horizontalMargin
+ width = maxWidth.coerceAtMost(paddedWidth)
+ anchorView?.let {
+ horizontalOffset = -width / 2 + it.width / 2
+ verticalOffset = -it.height / 2
+ if (it.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ horizontalOffset = -horizontalOffset
+ }
+
+ it.rootView.foreground = dimDrawable
+ }
+
+ with(listView!!) {
+ clipToOutline = true
+ background = dialogBackground
+ dividerHeight = listDividerHeight
+ }
+
+ // actual show takes into account updated ListView specs
+ super.show()
+ }
+
+ override fun setOnDismissListener(listener: PopupWindow.OnDismissListener?) {
+ dismissListener = listener
+ }
+}
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 09ba373..c20af07 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -604,7 +604,7 @@
setCompoundDrawablesRelative(selected.icon, null, null, null)
}
- val anchor = parent.requireViewById<ViewGroup>(R.id.controls_header)
+ val anchor = parent.requireViewById<View>(R.id.app_or_structure_spinner)
if (items.size == 1) {
spinner.setBackground(null)
anchor.setOnClickListener(null)
@@ -617,10 +617,7 @@
anchor.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
- popup = GlobalActionsPopupMenu(
- popupThemedContext,
- true /* isDropDownMode */
- ).apply {
+ popup = ControlsPopupMenu(popupThemedContext).apply {
setAnchorView(anchor)
setAdapter(adapter)
@@ -868,22 +865,24 @@
}
}
-private class ItemAdapter(
- val parentContext: Context,
- val resource: Int
-) : ArrayAdapter<SelectionItem>(parentContext, resource) {
+private class ItemAdapter(parentContext: Context, val resource: Int) :
+ ArrayAdapter<SelectionItem>(parentContext, resource) {
- val layoutInflater = LayoutInflater.from(context)
+ private val layoutInflater = LayoutInflater.from(context)!!
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- val item = getItem(position)
+ val item: SelectionItem = getItem(position)!!
val view = convertView ?: layoutInflater.inflate(resource, parent, false)
- view.requireViewById<TextView>(R.id.controls_spinner_item).apply {
- setText(item.getTitle())
- }
- view.requireViewById<ImageView>(R.id.app_icon).apply {
- setImageDrawable(item.icon)
+ with(view.tag as? ViewHolder ?: ViewHolder(view).also { view.tag = it }) {
+ titleView.text = item.getTitle()
+ iconView.setImageDrawable(item.icon)
}
return view
}
+
+ private class ViewHolder(itemView: View) {
+
+ val titleView: TextView = itemView.requireViewById(R.id.controls_spinner_item)
+ val iconView: ImageView = itemView.requireViewById(R.id.app_icon)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d4ed546..4fe219d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -137,7 +137,7 @@
* the digits when the clock moves.
*/
@JvmField
- val STEP_CLOCK_ANIMATION = releasedFlag(212, "step_clock_animation")
+ val STEP_CLOCK_ANIMATION = unreleasedFlag(212, "step_clock_animation", teamfood = true)
/**
* Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
@@ -569,10 +569,6 @@
val TRACKPAD_GESTURE_COMMON = releasedFlag(1210, "trackpad_gesture_common")
// 1300 - screenshots
- // TODO(b/254513155): Tracking Bug
- @JvmField
- val SCREENSHOT_WORK_PROFILE_POLICY = releasedFlag(1301, "screenshot_work_profile_policy")
-
// TODO(b/264916608): Tracking Bug
@JvmField val SCREENSHOT_METADATA = unreleasedFlag(1302, "screenshot_metadata", teamfood = true)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 5ecc00f..0825435 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2690,6 +2690,17 @@
mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
return;
}
+ if (apps == null || apps.length == 0) {
+ Slog.e(TAG, "Keyguard exit without a corresponding app to show.");
+ try {
+ finishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException");
+ } finally {
+ mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
+ }
+ return;
+ }
// TODO(bc-unlock): Sample animation, just to apply alpha animation on the app.
final SyncRtSurfaceTransactionApplier applier =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index ae5b799..64e2a2cb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.keyguard.data.repository
import android.os.Build
+import android.util.Log
import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -34,6 +35,7 @@
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
/**
* Encapsulates app state for the lock screen primary and alternate bouncer.
@@ -231,6 +233,7 @@
primaryBouncerShow
.logDiffsForTable(buffer, "", "PrimaryBouncerShow", false)
+ .onEach { Log.d(TAG, "Keyguard Bouncer is ${if (it) "showing" else "hiding."}") }
.launchIn(applicationScope)
primaryBouncerShowingSoon
.logDiffsForTable(buffer, "", "PrimaryBouncerShowingSoon", false)
@@ -274,5 +277,6 @@
companion object {
private const val NOT_VISIBLE = -1L
+ private const val TAG = "KeyguardBouncerRepositoryImpl"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index e65c8a1..77541e9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -95,8 +95,7 @@
}
val keyguardAuthenticated: Flow<Boolean> = repository.keyguardAuthenticated.filterNotNull()
- val show: Flow<Unit> = repository.primaryBouncerShow.filter { it }.map {}
- val hide: Flow<Unit> = repository.primaryBouncerShow.filter { !it }.map {}
+ val isShowing: Flow<Boolean> = repository.primaryBouncerShow
val startingToHide: Flow<Unit> = repository.primaryBouncerStartingToHide.filter { it }.map {}
val isBackButtonEnabled: Flow<Boolean> = repository.isBackButtonEnabled.filterNotNull()
val showMessage: Flow<BouncerShowMessageModel> = repository.showMessage.filterNotNull()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index 5fcf105..468a6b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -109,36 +109,36 @@
try {
viewModel.setBouncerViewDelegate(delegate)
launch {
- viewModel.show.collect {
- // Reset Security Container entirely.
- securityContainerController.reinflateViewFlipper {
+ viewModel.isShowing.collect { isShowing ->
+ if (isShowing) {
// Reset Security Container entirely.
- view.visibility = View.VISIBLE
+ securityContainerController.reinflateViewFlipper {
+ // Reset Security Container entirely.
+ view.visibility = View.VISIBLE
+ securityContainerController.onBouncerVisibilityChanged(
+ /* isVisible= */ true
+ )
+ securityContainerController.showPrimarySecurityScreen(
+ /* turningOff= */ false
+ )
+ securityContainerController.appear()
+ securityContainerController.onResume(
+ KeyguardSecurityView.SCREEN_ON
+ )
+ }
+ } else {
+ view.visibility = View.INVISIBLE
securityContainerController.onBouncerVisibilityChanged(
- /* isVisible= */ true
+ /* isVisible= */ false
)
- securityContainerController.showPrimarySecurityScreen(
- /* turningOff= */ false
- )
- securityContainerController.appear()
- securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
+ securityContainerController.cancelDismissAction()
+ securityContainerController.reset()
+ securityContainerController.onPause()
}
}
}
launch {
- viewModel.hide.collect {
- view.visibility = View.INVISIBLE
- securityContainerController.onBouncerVisibilityChanged(
- /* isVisible= */ false
- )
- securityContainerController.cancelDismissAction()
- securityContainerController.reset()
- securityContainerController.onPause()
- }
- }
-
- launch {
viewModel.startingToHide.collect {
securityContainerController.onStartingToHide()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
index 0656c9b..9602888 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -40,11 +40,8 @@
/** Can the user interact with the view? */
val isInteractable: Flow<Boolean> = interactor.isInteractable
- /** Observe whether bouncer is showing. */
- val show: Flow<Unit> = interactor.show
-
- /** Observe whether bouncer is hiding. */
- val hide: Flow<Unit> = interactor.hide
+ /** Observe whether bouncer is showing or not. */
+ val isShowing: Flow<Boolean> = interactor.isShowing
/** Observe whether bouncer is starting to hide. */
val startingToHide: Flow<Unit> = interactor.startingToHide
@@ -70,8 +67,8 @@
/** Observe whether we should update fps is showing. */
val shouldUpdateSideFps: Flow<Unit> =
merge(
- interactor.hide,
- interactor.show,
+ interactor.isShowing.map {},
+ interactor.startingToHide,
interactor.startingDisappearAnimation.filterNotNull().map {}
)
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 93ed859..d951ea5 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -18,6 +18,7 @@
package com.android.systemui.notetask
+import android.app.ActivityManager
import android.app.KeyguardManager
import android.app.admin.DevicePolicyManager
import android.app.role.OnRoleHoldersChangedListener
@@ -40,6 +41,7 @@
import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
import com.android.systemui.util.kotlin.getOrNull
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.Bubbles
@@ -67,6 +69,7 @@
private val optionalBubbles: Optional<Bubbles>,
private val userManager: UserManager,
private val keyguardManager: KeyguardManager,
+ private val activityManager: ActivityManager,
@NoteTaskEnabledKey private val isEnabled: Boolean,
private val devicePolicyManager: DevicePolicyManager,
private val userTracker: UserTracker,
@@ -151,9 +154,13 @@
logDebug { "onShowNoteTask - opened as app bubble: $info" }
}
is NoteTaskLaunchMode.Activity -> {
- context.startActivityAsUser(intent, user)
- eventLogger.logNoteTaskOpened(info)
- logDebug { "onShowNoteTask - opened as activity: $info" }
+ if (activityManager.isInForeground(info.packageName)) {
+ logDebug { "onShowNoteTask - already opened as activity: $info" }
+ } else {
+ context.startActivityAsUser(intent, user)
+ eventLogger.logNoteTaskOpened(info)
+ logDebug { "onShowNoteTask - opened as activity: $info" }
+ }
}
}
logDebug { "onShowNoteTask - success: $info" }
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index 8aed995..2da5b76 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -18,6 +18,11 @@
import android.content.Context
import android.hardware.input.InputSettings
+import android.os.Build
+import android.os.UserManager
+import android.util.Log
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
@@ -39,6 +44,7 @@
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
class NoteTaskQuickAffordanceConfig
@Inject
@@ -46,6 +52,8 @@
context: Context,
private val controller: NoteTaskController,
private val stylusManager: StylusManager,
+ private val keyguardMonitor: KeyguardUpdateMonitor,
+ private val userManager: UserManager,
private val lazyRepository: Lazy<KeyguardQuickAffordanceRepository>,
@NoteTaskEnabledKey private val isEnabled: Boolean,
) : KeyguardQuickAffordanceConfig {
@@ -61,17 +69,27 @@
// Due to a dependency cycle with KeyguardQuickAffordanceRepository, we need to lazily access
// the repository when lockScreenState is accessed for the first time.
override val lockScreenState by lazy {
- val stylusEverUsedFlow = createStylusEverUsedFlow(context, stylusManager)
- val configSelectedFlow = createConfigSelectedFlow(lazyRepository.get(), key)
- combine(configSelectedFlow, stylusEverUsedFlow) { isSelected, isStylusEverUsed ->
- if (isEnabled && (isSelected || isStylusEverUsed)) {
- val contentDescription = ContentDescription.Resource(pickerNameResourceId)
- val icon = Icon.Resource(pickerIconResourceId, contentDescription)
- LockScreenState.Visible(icon)
- } else {
- LockScreenState.Hidden
+ val repository = lazyRepository.get()
+ val configSelectedFlow = repository.createConfigSelectedFlow(key)
+ val stylusEverUsedFlow = stylusManager.createStylusEverUsedFlow(context)
+ val userUnlockedFlow = userManager.createUserUnlockedFlow(keyguardMonitor)
+ combine(userUnlockedFlow, stylusEverUsedFlow, configSelectedFlow) {
+ isUserUnlocked,
+ isStylusEverUsed,
+ isConfigSelected ->
+ logDebug { "lockScreenState:isUserUnlocked=$isUserUnlocked" }
+ logDebug { "lockScreenState:isStylusEverUsed=$isStylusEverUsed" }
+ logDebug { "lockScreenState:isConfigSelected=$isConfigSelected" }
+
+ if (isEnabled && isUserUnlocked && (isConfigSelected || isStylusEverUsed)) {
+ val contentDescription = ContentDescription.Resource(pickerNameResourceId)
+ val icon = Icon.Resource(pickerIconResourceId, contentDescription)
+ LockScreenState.Visible(icon)
+ } else {
+ LockScreenState.Hidden
+ }
}
- }
+ .onEach { state -> logDebug { "lockScreenState=$state" } }
}
override suspend fun getPickerScreenState() =
@@ -82,27 +100,40 @@
}
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
- controller.showNoteTask(
- entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE,
- )
+ controller.showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
return OnTriggeredResult.Handled
}
}
-private fun createStylusEverUsedFlow(context: Context, stylusManager: StylusManager) =
- callbackFlow {
- trySendBlocking(InputSettings.isStylusEverUsed(context))
- val callback =
- object : StylusManager.StylusCallback {
- override fun onStylusFirstUsed() {
- trySendBlocking(InputSettings.isStylusEverUsed(context))
- }
+private fun UserManager.createUserUnlockedFlow(monitor: KeyguardUpdateMonitor) = callbackFlow {
+ trySendBlocking(isUserUnlocked)
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onUserUnlocked() {
+ trySendBlocking(isUserUnlocked)
}
- stylusManager.registerCallback(callback)
- awaitClose { stylusManager.unregisterCallback(callback) }
- }
+ }
+ monitor.registerCallback(callback)
+ awaitClose { monitor.removeCallback(callback) }
+}
-private fun createConfigSelectedFlow(repository: KeyguardQuickAffordanceRepository, key: String) =
- repository.selections.map { selected ->
+private fun StylusManager.createStylusEverUsedFlow(context: Context) = callbackFlow {
+ trySendBlocking(InputSettings.isStylusEverUsed(context))
+ val callback =
+ object : StylusManager.StylusCallback {
+ override fun onStylusFirstUsed() {
+ trySendBlocking(InputSettings.isStylusEverUsed(context))
+ }
+ }
+ registerCallback(callback)
+ awaitClose { unregisterCallback(callback) }
+}
+
+private fun KeyguardQuickAffordanceRepository.createConfigSelectedFlow(key: String) =
+ selections.map { selected ->
selected.values.flatten().any { selectedConfig -> selectedConfig.key == key }
}
+
+private inline fun Any.logDebug(message: () -> String) {
+ if (Build.IS_DEBUGGABLE) Log.d(this::class.java.simpleName, message())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 7a42642..c2c1306 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -772,9 +772,7 @@
mSaverConfirmation.dismiss();
}
// Also close the notification shade, if it's open.
- mBroadcastSender.sendBroadcast(
- new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
- .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
+ mBroadcastSender.closeSystemDialogs();
final Uri uri = Uri.parse(getURL());
Context context = widget.getContext();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 0748bcb..c28a40a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -140,7 +140,8 @@
private final Handler mHandler;
private final Lazy<NavigationBarController> mNavBarControllerLazy;
private final NotificationShadeWindowController mStatusBarWinController;
- private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
+ private final Runnable mConnectionRunnable = () ->
+ internalConnectToCurrentUser("runnable: startConnectionToCurrentUser");
private final ComponentName mRecentsComponentName;
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
@@ -406,7 +407,7 @@
// Failed to link to death (process may have died between binding and connecting),
// just unbind the service for now and retry again
Log.e(TAG_OPS, "Lost connection to launcher service", e);
- disconnectFromLauncherService();
+ disconnectFromLauncherService("Lost connection to launcher service");
retryConnectionWithBackoff();
return;
}
@@ -501,7 +502,7 @@
@Override
public void onUserChanged(int newUser, @NonNull Context userContext) {
mConnectionBackoffAttempts = 0;
- internalConnectToCurrentUser();
+ internalConnectToCurrentUser("User changed");
}
};
@@ -716,12 +717,12 @@
if (mHandler.getLooper() != Looper.myLooper()) {
mHandler.post(mConnectionRunnable);
} else {
- internalConnectToCurrentUser();
+ internalConnectToCurrentUser("startConnectionToCurrentUser");
}
}
- private void internalConnectToCurrentUser() {
- disconnectFromLauncherService();
+ private void internalConnectToCurrentUser(String reason) {
+ disconnectFromLauncherService(reason);
// If user has not setup yet or already connected, do not try to connect
if (!isEnabled()) {
@@ -783,7 +784,9 @@
return mOverviewProxy;
}
- private void disconnectFromLauncherService() {
+ private void disconnectFromLauncherService(String disconnectReason) {
+ Log.d(TAG_OPS, "disconnectFromLauncherService bound?: " + mBound +
+ " currentProxy: " + mOverviewProxy + " disconnectReason: " + disconnectReason);
if (mBound) {
// Always unbind the service (ie. if called through onNullBinding or onBindingDied)
mContext.unbindService(mOverviewServiceConnection);
@@ -1047,6 +1050,6 @@
mContext.unregisterReceiver(mLauncherStateChangedReceiver);
mIsEnabled = false;
mHandler.removeCallbacks(mConnectionRunnable);
- disconnectFromLauncherService();
+ disconnectFromLauncherService("Shutdown for test");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 0477626..4349bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -205,7 +205,7 @@
}, false, false);
// Close quick shade
- sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ closeSystemDialogs();
break;
}
return Service.START_STICKY;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index 7cfe232..8c01bae 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -39,7 +39,6 @@
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;
@@ -294,8 +293,7 @@
final ContentValues values = createMetadata(time, format, fileName);
Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- if (flags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)
- && UserHandle.myUserId() != owner.getIdentifier()) {
+ if (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/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 02a60ad..2312c70 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -47,7 +47,6 @@
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.screenshot.ScrollCaptureController.LongScreenshot;
import com.android.systemui.settings.UserTracker;
@@ -335,8 +334,7 @@
}
private void doEdit(Uri uri) {
- if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY) && mScreenshotUserHandle
- != Process.myUserHandle()) {
+ if (mScreenshotUserHandle != Process.myUserHandle()) {
// TODO: Fix transition for work profile. Omitting it in the meantime.
mActionExecutor.launchIntentAsync(
ActionIntentCreator.INSTANCE.createEditIntent(uri, this),
@@ -365,21 +363,9 @@
}
private void doShare(Uri uri) {
- if (mFeatureFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
- Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri);
- mActionExecutor.launchIntentAsync(shareIntent, null,
- mScreenshotUserHandle.getIdentifier(), false);
- } else {
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setType("image/png");
- intent.putExtra(Intent.EXTRA_STREAM, uri);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_GRANT_READ_URI_PERMISSION);
- Intent sharingChooserIntent = Intent.createChooser(intent, null)
- .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- startActivityAsUser(sharingChooserIntent, mUserTracker.getUserHandle());
- }
+ Intent shareIntent = ActionIntentCreator.INSTANCE.createShareIntent(uri);
+ mActionExecutor.launchIntentAsync(shareIntent, null,
+ mScreenshotUserHandle.getIdentifier(), false);
}
private void onClicked(View v) {
@@ -421,8 +407,7 @@
mOutputBitmap = renderBitmap(drawable, bounds);
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
mBackgroundExecutor, UUID.randomUUID(), mOutputBitmap, ZonedDateTime.now(),
- mFeatureFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)
- ? mScreenshotUserHandle : Process.myUserHandle());
+ mScreenshotUserHandle);
exportFuture.addListener(() -> onExportCompleted(action, exportFuture), mUiExecutor);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
index ad66514..b4ffabd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
@@ -47,48 +47,43 @@
// Minimal implementation for use when Flags.SCREENSHOT_METADATA isn't turned on.
fun onScreenshotTaken(userHandle: UserHandle) {
- if (featureFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
- val workProfileData = workProfileMessageController.onScreenshotTaken(userHandle)
- if (workProfileData != null) {
- workProfileFirstRunView.visibility = View.VISIBLE
- detectionNoticeView.visibility = View.GONE
+ val workProfileData = workProfileMessageController.onScreenshotTaken(userHandle)
+ if (workProfileData != null) {
+ workProfileFirstRunView.visibility = View.VISIBLE
+ detectionNoticeView.visibility = View.GONE
- workProfileMessageController.populateView(
- workProfileFirstRunView,
- workProfileData,
- this::animateOutMessageContainer
- )
- animateInMessageContainer()
- }
+ workProfileMessageController.populateView(
+ workProfileFirstRunView,
+ workProfileData,
+ this::animateOutMessageContainer
+ )
+ animateInMessageContainer()
}
}
fun onScreenshotTaken(screenshot: ScreenshotData) {
- if (featureFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
- val workProfileData =
- workProfileMessageController.onScreenshotTaken(screenshot.userHandle)
- var notifiedApps: List<CharSequence> = listOf()
- if (featureFlags.isEnabled(Flags.SCREENSHOT_DETECTION)) {
- notifiedApps = screenshotDetectionController.maybeNotifyOfScreenshot(screenshot)
- }
+ val workProfileData = workProfileMessageController.onScreenshotTaken(screenshot.userHandle)
+ var notifiedApps: List<CharSequence> = listOf()
+ if (featureFlags.isEnabled(Flags.SCREENSHOT_DETECTION)) {
+ notifiedApps = screenshotDetectionController.maybeNotifyOfScreenshot(screenshot)
+ }
- // If work profile first run needs to show, bias towards that, otherwise show screenshot
- // detection notification if needed.
- if (workProfileData != null) {
- workProfileFirstRunView.visibility = View.VISIBLE
- detectionNoticeView.visibility = View.GONE
- workProfileMessageController.populateView(
- workProfileFirstRunView,
- workProfileData,
- this::animateOutMessageContainer
- )
- animateInMessageContainer()
- } else if (notifiedApps.isNotEmpty()) {
- detectionNoticeView.visibility = View.VISIBLE
- workProfileFirstRunView.visibility = View.GONE
- screenshotDetectionController.populateView(detectionNoticeView, notifiedApps)
- animateInMessageContainer()
- }
+ // If work profile first run needs to show, bias towards that, otherwise show screenshot
+ // detection notification if needed.
+ if (workProfileData != null) {
+ workProfileFirstRunView.visibility = View.VISIBLE
+ detectionNoticeView.visibility = View.GONE
+ workProfileMessageController.populateView(
+ workProfileFirstRunView,
+ workProfileData,
+ this::animateOutMessageContainer
+ )
+ animateInMessageContainer()
+ } else if (notifiedApps.isNotEmpty()) {
+ detectionNoticeView.visibility = View.VISIBLE
+ workProfileFirstRunView.visibility = View.GONE
+ screenshotDetectionController.populateView(detectionNoticeView, notifiedApps)
+ animateInMessageContainer()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index 4db48ac..c0d807a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -23,7 +23,6 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.function.Consumer
@@ -57,9 +56,7 @@
// Whenever displayContentInfo is fetched, the topComponent is also populated
// regardless of the managed profile status.
- if (request.type != TAKE_SCREENSHOT_PROVIDED_IMAGE &&
- flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
- ) {
+ if (request.type != TAKE_SCREENSHOT_PROVIDED_IMAGE) {
val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
Log.d(TAG, "findPrimaryContent: $info")
@@ -118,9 +115,7 @@
// Whenever displayContentInfo is fetched, the topComponent is also populated
// regardless of the managed profile status.
- if (screenshot.type != TAKE_SCREENSHOT_PROVIDED_IMAGE &&
- flags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
- ) {
+ if (screenshot.type != TAKE_SCREENSHOT_PROVIDED_IMAGE) {
val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
Log.d(TAG, "findPrimaryContent: $info")
result.taskId = info.taskId
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index bf5fbd2..efd79d7 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -49,7 +49,6 @@
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.R;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
import com.google.common.util.concurrent.ListenableFuture;
@@ -121,16 +120,13 @@
}
// TODO: move to constructor / from ScreenshotRequest
final UUID requestId = UUID.randomUUID();
- final UserHandle user = mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)
- ? mParams.owner : getUserHandleOfForegroundApplication(mContext);
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Bitmap image = mParams.image;
mScreenshotId = String.format(SCREENSHOT_ID_TEMPLATE, requestId);
- boolean savingToOtherUser = mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)
- && (user != Process.myUserHandle());
+ boolean savingToOtherUser = mParams.owner != Process.myUserHandle();
// Smart actions don't yet work for cross-user saves.
boolean smartActionsEnabled = !savingToOtherUser
&& DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
@@ -141,7 +137,7 @@
// Since Quick Share target recommendation does not rely on image URL, it is
// queried and surfaced before image compress/export. Action intent would not be
// used, because it does not contain image URL.
- queryQuickShareAction(image, user);
+ queryQuickShareAction(image, mParams.owner);
}
// Call synchronously here since already on a background thread.
@@ -156,7 +152,7 @@
mScreenshotSmartActions.getSmartActionsFuture(
mScreenshotId, uri, image, mSmartActionsProvider,
ScreenshotSmartActionType.REGULAR_SMART_ACTIONS,
- smartActionsEnabled, user);
+ smartActionsEnabled, mParams.owner);
List<Notification.Action> smartActions = new ArrayList<>();
if (smartActionsEnabled) {
int timeoutMs = DeviceConfig.getInt(
@@ -172,7 +168,7 @@
}
mImageData.uri = uri;
- mImageData.owner = user;
+ mImageData.owner = mParams.owner;
mImageData.smartActions = smartActions;
mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri,
smartActionsEnabled);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 7ad594e..b2ae4a0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -19,7 +19,6 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
-import static com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY;
import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
@@ -471,16 +470,12 @@
}
prepareAnimation(screenshot.getScreenBounds(), showFlash, () -> {
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mMessageContainerController.onScreenshotTaken(screenshot);
- }
+ mMessageContainerController.onScreenshotTaken(screenshot);
});
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
- mContext.getDrawable(R.drawable.overlay_badge_background),
- screenshot.getUserHandle()));
- }
+ mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
+ mContext.getDrawable(R.drawable.overlay_badge_background),
+ screenshot.getUserHandle()));
mScreenshotView.setScreenshot(screenshot);
if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && screenshot.getTaskId() >= 0) {
@@ -505,8 +500,7 @@
void prepareViewForNewScreenshot(ScreenshotData screenshot, String oldPackageName) {
withWindowAttached(() -> {
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
- && mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) {
+ if (mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) {
mScreenshotView.announceForAccessibility(mContext.getResources().getString(
R.string.screenshot_saving_work_profile_title));
} else {
@@ -640,9 +634,7 @@
// Inflate the screenshot layout
mScreenshotView = (ScreenshotView)
LayoutInflater.from(mContext).inflate(R.layout.screenshot, null);
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mMessageContainerController.setView(mScreenshotView);
- }
+ mMessageContainerController.setView(mScreenshotView);
mScreenshotView.addOnAttachStateChangeListener(
new View.OnAttachStateChangeListener() {
@Override
@@ -740,8 +732,7 @@
private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
Insets screenInsets, ComponentName topComponent, boolean showFlash, UserHandle owner) {
withWindowAttached(() -> {
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
- && mUserManager.isManagedProfile(owner.getIdentifier())) {
+ if (mUserManager.isManagedProfile(owner.getIdentifier())) {
mScreenshotView.announceForAccessibility(mContext.getResources().getString(
R.string.screenshot_saving_work_profile_title));
} else {
@@ -793,15 +784,11 @@
attachWindow();
prepareAnimation(screenRect, showFlash, () -> {
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mMessageContainerController.onScreenshotTaken(owner);
- }
+ mMessageContainerController.onScreenshotTaken(owner);
});
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
- mContext.getDrawable(R.drawable.overlay_badge_background), owner));
- }
+ mScreenshotView.badgeScreenshot(mContext.getPackageManager().getUserBadgedIcon(
+ mContext.getDrawable(R.drawable.overlay_badge_background), owner));
mScreenshotView.setScreenshot(mScreenBitmap, screenInsets);
if (DEBUG_WINDOW) {
Log.d(TAG, "setContentView: " + mScreenshotView);
@@ -959,7 +946,7 @@
transitionDestination, onTransitionEnd,
longScreenshot);
// TODO: Do this via ActionIntentExecutor instead.
- mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ mContext.closeSystemDialogs();
}
);
@@ -1274,8 +1261,7 @@
R.string.screenshot_failed_to_save_text);
} else {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, mPackageName);
- if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
- && mUserManager.isManagedProfile(imageData.owner.getIdentifier())) {
+ if (mUserManager.isManagedProfile(imageData.owner.getIdentifier())) {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED_TO_WORK_PROFILE, 0,
mPackageName);
}
@@ -1283,13 +1269,8 @@
}
private boolean isUserSetupComplete(UserHandle owner) {
- 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;
- }
+ return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
+ .getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 80f2717..093c09f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -36,7 +36,6 @@
import android.app.ActivityManager;
import android.app.BroadcastOptions;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
@@ -91,7 +90,6 @@
import com.android.systemui.R;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
-import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
@@ -798,49 +796,36 @@
void setChipIntents(ScreenshotController.SavedImageData imageData) {
mShareChip.setOnClickListener(v -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED, 0, mPackageName);
- if (mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
- prepareSharedTransition();
+ prepareSharedTransition();
- Intent shareIntent;
- if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && mScreenshotData != null
- && mScreenshotData.getContextUrl() != null) {
- shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithExtraText(
- imageData.uri, mScreenshotData.getContextUrl().toString());
- } else {
- shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithSubject(
- imageData.uri, imageData.subject);
- }
- mActionExecutor.launchIntentAsync(shareIntent,
- imageData.shareTransition.get().bundle,
- imageData.owner.getIdentifier(), false);
+ Intent shareIntent;
+ if (mFlags.isEnabled(Flags.SCREENSHOT_METADATA) && mScreenshotData != null
+ && mScreenshotData.getContextUrl() != null) {
+ shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithExtraText(
+ imageData.uri, mScreenshotData.getContextUrl().toString());
} else {
- startSharedTransition(imageData.shareTransition.get());
+ shareIntent = ActionIntentCreator.INSTANCE.createShareIntentWithSubject(
+ imageData.uri, imageData.subject);
}
+ mActionExecutor.launchIntentAsync(shareIntent,
+ imageData.shareTransition.get().bundle,
+ imageData.owner.getIdentifier(), false);
});
mEditChip.setOnClickListener(v -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName);
- if (mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
- prepareSharedTransition();
- mActionExecutor.launchIntentAsync(
- ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
- imageData.editTransition.get().bundle,
- imageData.owner.getIdentifier(), true);
- } else {
- startSharedTransition(imageData.editTransition.get());
- }
+ prepareSharedTransition();
+ mActionExecutor.launchIntentAsync(
+ ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
+ imageData.editTransition.get().bundle,
+ imageData.owner.getIdentifier(), true);
});
mScreenshotPreview.setOnClickListener(v -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName);
- if (mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)) {
- prepareSharedTransition();
- mActionExecutor.launchIntentAsync(
- ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
- imageData.editTransition.get().bundle,
- imageData.owner.getIdentifier(), true);
- } else {
- startSharedTransition(
- imageData.editTransition.get());
- }
+ prepareSharedTransition();
+ mActionExecutor.launchIntentAsync(
+ ActionIntentCreator.INSTANCE.createEditIntent(imageData.uri, mContext),
+ imageData.editTransition.get().bundle,
+ imageData.owner.getIdentifier(), true);
});
if (mQuickShareChip != null) {
if (imageData.quickShareAction != null) {
@@ -1115,22 +1100,6 @@
mScreenshotData = null;
}
- private void startSharedTransition(ActionTransition transition) {
- try {
- mPendingSharedTransition = true;
- transition.action.actionIntent.send(mInteractiveBroadcastOption);
-
- // fade out non-preview UI
- createScreenshotFadeDismissAnimation().start();
- } catch (PendingIntent.CanceledException e) {
- mPendingSharedTransition = false;
- if (transition.onCancelRunnable != null) {
- transition.onCancelRunnable.run();
- }
- Log.e(TAG, "Intent cancelled", e);
- }
- }
-
private void prepareSharedTransition() {
mPendingSharedTransition = true;
// fade out non-preview UI
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 111278a..7ac0fd5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -21,7 +21,6 @@
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_COMPLETE;
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
-import static com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY;
import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
import static com.android.systemui.screenshot.LogConfig.DEBUG_SERVICE;
@@ -59,7 +58,6 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.FlagListenable.FlagEvent;
import com.android.systemui.flags.Flags;
import java.util.concurrent.Executor;
@@ -123,7 +121,6 @@
mContext = context;
mBgExecutor = bgExecutor;
mFeatureFlags = featureFlags;
- mFeatureFlags.addListener(SCREENSHOT_WORK_PROFILE_POLICY, FlagEvent::requestNoRestart);
mProcessor = processor;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index fbcc9ff..1cb314a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -37,6 +37,7 @@
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPENING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
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;
@@ -3457,7 +3458,9 @@
Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
+ isFullyExpanded() + " inQs=" + mQsController.getExpanded());
}
- mSysUiState.setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+ mSysUiState
+ .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, getExpandedFraction() > 0)
+ .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
isFullyExpanded() && !mQsController.getExpanded())
.setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
isFullyExpanded() && mQsController.getExpanded()).commitUpdate(mDisplayId);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index 9f46707..07c8e52 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -25,6 +25,7 @@
import static com.android.systemui.shade.NotificationPanelViewController.FLING_HIDE;
import static com.android.systemui.shade.NotificationPanelViewController.QS_PARALLAX_AMOUNT;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -258,6 +259,12 @@
/** The duration of the notification bounds animation. */
private long mNotificationBoundsAnimationDuration;
+ /** TODO(b/273591201): remove after bug resolved */
+ private int mLastClippingTopBound;
+ private int mLastNotificationsTopPadding;
+ private int mLastNotificationsClippingTopBound;
+ private int mLastNotificationsClippingTopBoundNssl;
+
private final Region mInterceptRegion = new Region();
/** The end bounds of a clipping animation. */
private final Rect mClippingAnimationEndBounds = new Rect();
@@ -643,7 +650,7 @@
float appearAmount = mNotificationStackScrollLayoutController
.calculateAppearFraction(mShadeExpandedHeight);
float startHeight = -getExpansionHeight();
- if (mBarState == StatusBarState.SHADE) {
+ if (mBarState == SHADE) {
// Small parallax as we pull down and clip QS
startHeight = -getExpansionHeight() * QS_PARALLAX_AMOUNT;
}
@@ -1123,6 +1130,7 @@
mClippingAnimationEndBounds.left, fraction);
int animTop = (int) MathUtils.lerp(startTop,
mClippingAnimationEndBounds.top, fraction);
+ logClippingTopBound("interpolated top bound", top);
int animRight = (int) MathUtils.lerp(startRight,
mClippingAnimationEndBounds.right, fraction);
int animBottom = (int) MathUtils.lerp(startBottom,
@@ -1243,6 +1251,8 @@
// the screen without clipping.
return -mAmbientState.getStackTopMargin();
} else {
+ logNotificationsClippingTopBound(qsTop,
+ mNotificationStackScrollLayoutController.getTop());
return qsTop - mNotificationStackScrollLayoutController.getTop();
}
}
@@ -1265,6 +1275,7 @@
/** Calculate top padding for notifications */
public float calculateNotificationsTopPadding(boolean isShadeExpanding,
int keyguardNotificationStaticPadding, float expandedFraction) {
+ float topPadding;
boolean keyguardShowing = mBarState == KEYGUARD;
if (mSplitShadeEnabled) {
return keyguardShowing
@@ -1281,19 +1292,27 @@
int maxQsPadding = getMaxExpansionHeight();
int max = keyguardShowing ? Math.max(
keyguardNotificationStaticPadding, maxQsPadding) : maxQsPadding;
- return (int) MathUtils.lerp((float) getMinExpansionHeight(),
+ topPadding = (int) MathUtils.lerp((float) getMinExpansionHeight(),
(float) max, expandedFraction);
+ logNotificationsTopPadding("keyguard and expandImmediate", topPadding);
+ return topPadding;
} else if (isSizeChangeAnimationRunning()) {
- return Math.max((int) mSizeChangeAnimator.getAnimatedValue(),
+ topPadding = Math.max((int) mSizeChangeAnimator.getAnimatedValue(),
keyguardNotificationStaticPadding);
+ logNotificationsTopPadding("size change animation running", topPadding);
+ return topPadding;
} else if (keyguardShowing) {
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
- return MathUtils.lerp((float) keyguardNotificationStaticPadding,
+ topPadding = MathUtils.lerp((float) keyguardNotificationStaticPadding,
(float) (getMaxExpansionHeight()), computeExpansionFraction());
+ logNotificationsTopPadding("keyguard", topPadding);
+ return topPadding;
} else {
- return mQsFrameTranslateController.getNotificationsTopPadding(
+ topPadding = mQsFrameTranslateController.getNotificationsTopPadding(
mExpansionHeight, mNotificationStackScrollLayoutController);
+ logNotificationsTopPadding("default case", topPadding);
+ return topPadding;
}
}
@@ -1340,6 +1359,38 @@
- mAmbientState.getScrollY());
}
+ /** TODO(b/273591201): remove after bug resolved */
+ private void logNotificationsTopPadding(String message, float rawPadding) {
+ int padding = ((int) rawPadding / 10) * 10;
+ if (mBarState != KEYGUARD && padding != mLastNotificationsTopPadding && !mExpanded) {
+ mLastNotificationsTopPadding = padding;
+ mShadeLog.logNotificationsTopPadding(message, padding);
+ }
+ }
+
+ /** TODO(b/273591201): remove after bug resolved */
+ private void logClippingTopBound(String message, int top) {
+ top = (top / 10) * 10;
+ if (mBarState != KEYGUARD && mShadeExpandedFraction == 1
+ && top != mLastClippingTopBound && !mExpanded) {
+ mLastClippingTopBound = top;
+ mShadeLog.logClippingTopBound(message, top);
+ }
+ }
+
+ /** TODO(b/273591201): remove after bug resolved */
+ private void logNotificationsClippingTopBound(int top, int nsslTop) {
+ top = (top / 10) * 10;
+ nsslTop = (nsslTop / 10) * 10;
+ if (mBarState == SHADE && mShadeExpandedFraction == 1
+ && (top != mLastNotificationsClippingTopBound
+ || nsslTop != mLastNotificationsClippingTopBoundNssl) && !mExpanded) {
+ mLastNotificationsClippingTopBound = top;
+ mLastNotificationsClippingTopBoundNssl = nsslTop;
+ mShadeLog.logNotificationsClippingTopBound(top, nsslTop);
+ }
+ }
+
private int calculateTopClippingBound(int qsPanelBottomY) {
int top;
if (mSplitShadeEnabled) {
@@ -1349,6 +1400,7 @@
// If we're transitioning, let's use the actual value. The else case
// can be wrong during transitions when waiting for the keyguard to unlock
top = mTransitionToFullShadePosition;
+ logClippingTopBound("set while transitioning to full shade", top);
} else {
final float notificationTop = getEdgePosition();
if (mBarState == KEYGUARD) {
@@ -1357,8 +1409,10 @@
// this should go away once we unify the stackY position and don't have
// to do this min anymore below.
top = qsPanelBottomY;
+ logClippingTopBound("bypassing keyguard", top);
} else {
top = (int) Math.min(qsPanelBottomY, notificationTop);
+ logClippingTopBound("keyguard default case", top);
}
} else {
top = (int) notificationTop;
@@ -1366,12 +1420,14 @@
}
// TODO (b/265193930): remove dependency on NPVC
top += mPanelViewControllerLazy.get().getOverStretchAmount();
+ logClippingTopBound("including overstretch", top);
// Correction for instant expansion caused by HUN pull down/
float minFraction = mPanelViewControllerLazy.get().getMinFraction();
if (minFraction > 0f && minFraction < 1f) {
float realFraction = (mShadeExpandedFraction
- minFraction) / (1f - minFraction);
top *= MathUtils.saturate(realFraction / minFraction);
+ logClippingTopBound("after adjusted fraction", top);
}
}
return top;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index d34e127..da4944c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -280,4 +280,40 @@
{ "Split shade state changed: split shade ${if (bool1) "enabled" else "disabled"}" }
)
}
+
+ fun logNotificationsTopPadding(message: String, padding: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = message
+ int1 = padding
+ },
+ { "QSC NotificationsTopPadding $str1: $int1"}
+ )
+ }
+
+ fun logClippingTopBound(message: String, top: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = message
+ int1 = top
+ },
+ { "QSC ClippingTopBound $str1: $int1" }
+ )
+ }
+
+ fun logNotificationsClippingTopBound(top: Int, nsslTop: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ int1 = top
+ int2 = nsslTop
+ },
+ { "QSC NotificationsClippingTopBound set to $int1 - $int2" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 4065b98..0205523 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -110,6 +110,8 @@
private final PipelineState mPipelineState = new PipelineState();
private final Map<String, GroupEntry> mGroups = new ArrayMap<>();
private Collection<NotificationEntry> mAllEntries = Collections.emptyList();
+ @Nullable
+ private Collection<NotificationEntry> mPendingEntries = null;
private int mIterationCount = 0;
private final List<NotifFilter> mNotifPreGroupFilters = new ArrayList<>();
@@ -317,11 +319,9 @@
@Override
public void onBuildList(Collection<NotificationEntry> entries, String reason) {
Assert.isMainThread();
- mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
-
+ mPendingEntries = new ArrayList<>(entries);
mLogger.logOnBuildList(reason);
- mAllEntries = entries;
- scheduleRebuild(/* reentrant = */ false);
+ rebuildListIfBefore(STATE_BUILD_STARTED);
}
};
@@ -398,6 +398,11 @@
Trace.beginSection("ShadeListBuilder.buildList");
mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
+ if (mPendingEntries != null) {
+ mAllEntries = mPendingEntries;
+ mPendingEntries = null;
+ }
+
if (!mNotifStabilityManager.isPipelineRunAllowed()) {
mLogger.logPipelineRunSuppressed();
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
index fc9d9e8..797038d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
@@ -28,6 +28,7 @@
import androidx.annotation.ColorInt;
+import com.android.internal.util.ContrastColorUtil;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -109,7 +110,7 @@
public void bind(@Nullable CharSequence title, @Nullable CharSequence text,
@Nullable View contentView) {
- mTitleView.setText(title);
+ mTitleView.setText(title.toString());
mTitleView.setVisibility(TextUtils.isEmpty(title) ? GONE : VISIBLE);
if (TextUtils.isEmpty(text)) {
mTextView.setVisibility(GONE);
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 7f13bd8..2bc09a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1485,16 +1485,16 @@
private void onPanelExpansionChanged(ShadeExpansionChangeEvent event) {
float fraction = event.getFraction();
boolean tracking = event.getTracking();
- boolean isExpanded = event.getExpanded();
dispatchPanelExpansionForKeyguardDismiss(fraction, tracking);
+ if (getNotificationPanelViewController() != null) {
+ getNotificationPanelViewController().updateSystemUiStateFlags();
+ }
+
if (fraction == 0 || fraction == 1) {
if (getNavigationBarView() != null) {
getNavigationBarView().onStatusBarPanelStateChanged();
}
- if (getNotificationPanelViewController() != null) {
- getNotificationPanelViewController().updateSystemUiStateFlags();
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 4866f73..a08aa88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -78,6 +78,7 @@
import com.android.internal.graphics.ColorUtils;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.InterpolatorsAndroidX;
@@ -221,7 +222,7 @@
final int stroke = colorized ? mContext.getResources().getDimensionPixelSize(
R.dimen.remote_input_view_text_stroke) : 0;
if (colorized) {
- final boolean dark = Notification.Builder.isColorDark(backgroundColor);
+ final boolean dark = ContrastColorUtil.isColorDark(backgroundColor);
final int foregroundColor = dark ? Color.WHITE : Color.BLACK;
final int inverseColor = dark ? Color.BLACK : Color.WHITE;
editBgColor = backgroundColor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index a537b2a..9e88ceb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -726,7 +726,7 @@
mCurrentBackgroundColor = backgroundColor;
mCurrentColorized = colorized;
- final boolean dark = Notification.Builder.isColorDark(backgroundColor);
+ final boolean dark = ContrastColorUtil.isColorDark(backgroundColor);
mCurrentTextColor = ContrastColorUtil.ensureTextContrast(
dark ? mDefaultTextColorDarkBg : mDefaultTextColor,
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
index 7b8235a..518f5a7 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsController.kt
@@ -16,8 +16,7 @@
package com.android.systemui.wallet.controller
-import android.Manifest
-import android.content.Context
+import android.content.Intent
import android.content.IntentFilter
import android.service.quickaccesswallet.GetWalletCardsError
import android.service.quickaccesswallet.GetWalletCardsResponse
@@ -32,13 +31,21 @@
import com.android.systemui.flags.Flags
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emptyFlow
-import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class WalletContextualSuggestionsController
@Inject
@@ -48,68 +55,99 @@
broadcastDispatcher: BroadcastDispatcher,
featureFlags: FeatureFlags
) {
+ private val cardsReceivedCallbacks: MutableSet<(List<WalletCard>) -> Unit> = mutableSetOf()
+
private val allWalletCards: Flow<List<WalletCard>> =
if (featureFlags.isEnabled(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)) {
- conflatedCallbackFlow {
- val callback =
- object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
- override fun onWalletCardsRetrieved(response: GetWalletCardsResponse) {
- trySendWithFailureLogging(response.walletCards, TAG)
- }
+ // TODO(b/237409756) determine if we should debounce this so we don't call the service
+ // too frequently. Also check if the list actually changed before calling callbacks.
+ broadcastDispatcher
+ .broadcastFlow(IntentFilter(Intent.ACTION_SCREEN_ON))
+ .flatMapLatest {
+ conflatedCallbackFlow {
+ val callback =
+ object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
+ override fun onWalletCardsRetrieved(
+ response: GetWalletCardsResponse
+ ) {
+ trySendWithFailureLogging(response.walletCards, TAG)
+ }
- override fun onWalletCardRetrievalError(error: GetWalletCardsError) {
- trySendWithFailureLogging(emptyList<WalletCard>(), TAG)
+ override fun onWalletCardRetrievalError(
+ error: GetWalletCardsError
+ ) {
+ trySendWithFailureLogging(emptyList<WalletCard>(), TAG)
+ }
+ }
+
+ walletController.setupWalletChangeObservers(
+ callback,
+ QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ )
+ walletController.updateWalletPreference()
+ walletController.queryWalletCards(callback)
+
+ awaitClose {
+ walletController.unregisterWalletChangeObservers(
+ QuickAccessWalletController.WalletChangeEvent
+ .WALLET_PREFERENCE_CHANGE,
+ QuickAccessWalletController.WalletChangeEvent
+ .DEFAULT_PAYMENT_APP_CHANGE
+ )
}
}
-
- walletController.setupWalletChangeObservers(
- callback,
- QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
- QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+ }
+ .onEach { notifyCallbacks(it) }
+ .stateIn(
+ applicationCoroutineScope,
+ // Needs to be done eagerly since we need to notify callbacks even if there are
+ // no subscribers
+ SharingStarted.Eagerly,
+ emptyList()
)
- walletController.updateWalletPreference()
- walletController.queryWalletCards(callback)
-
- awaitClose {
- walletController.unregisterWalletChangeObservers(
- QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
- QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
- )
- }
- }
} else {
emptyFlow()
}
- private val contextualSuggestionsCardIds: Flow<Set<String>> =
- if (featureFlags.isEnabled(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)) {
- broadcastDispatcher.broadcastFlow(
- filter = IntentFilter(ACTION_UPDATE_WALLET_CONTEXTUAL_SUGGESTIONS),
- permission = Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE,
- flags = Context.RECEIVER_EXPORTED
- ) { intent, _ ->
- if (intent.hasExtra(UPDATE_CARD_IDS_EXTRA)) {
- intent.getStringArrayListExtra(UPDATE_CARD_IDS_EXTRA).toSet()
- } else {
- emptySet()
- }
- }
- } else {
- emptyFlow()
- }
+ private val _suggestionCardIds: MutableStateFlow<Set<String>> = MutableStateFlow(emptySet())
+ private val contextualSuggestionsCardIds: Flow<Set<String>> = _suggestionCardIds.asStateFlow()
val contextualSuggestionCards: Flow<List<WalletCard>> =
combine(allWalletCards, contextualSuggestionsCardIds) { cards, ids ->
- cards.filter { card -> ids.contains(card.cardId) }
+ val ret =
+ cards.filter { card ->
+ card.cardType == WalletCard.CARD_TYPE_NON_PAYMENT &&
+ ids.contains(card.cardId)
+ }
+ ret
}
- .shareIn(applicationCoroutineScope, replay = 1, started = SharingStarted.Eagerly)
+ .stateIn(applicationCoroutineScope, SharingStarted.WhileSubscribed(), emptyList())
+
+ /** When called, {@link contextualSuggestionCards} will be updated to be for these IDs. */
+ fun setSuggestionCardIds(cardIds: Set<String>) {
+ _suggestionCardIds.update { _ -> cardIds }
+ }
+
+ /** Register callback to be called when a new list of cards is fetched. */
+ fun registerWalletCardsReceivedCallback(callback: (List<WalletCard>) -> Unit) {
+ cardsReceivedCallbacks.add(callback)
+ }
+
+ /** Unregister callback to be called when a new list of cards is fetched. */
+ fun unregisterWalletCardsReceivedCallback(callback: (List<WalletCard>) -> Unit) {
+ cardsReceivedCallbacks.remove(callback)
+ }
+
+ private fun notifyCallbacks(cards: List<WalletCard>) {
+ applicationCoroutineScope.launch {
+ cardsReceivedCallbacks.onEach { callback ->
+ callback(cards.filter { card -> card.cardType == WalletCard.CARD_TYPE_NON_PAYMENT })
+ }
+ }
+ }
companion object {
- private const val ACTION_UPDATE_WALLET_CONTEXTUAL_SUGGESTIONS =
- "com.android.systemui.wallet.UPDATE_CONTEXTUAL_SUGGESTIONS"
-
- private const val UPDATE_CARD_IDS_EXTRA = "cardIds"
-
private const val TAG = "WalletSuggestions"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java
index 7a31fa5..f9f14e0 100644
--- a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java
@@ -97,7 +97,7 @@
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
registerReceiver(mWifiChangeReceiver, filter);
// Close quick shade
- sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ closeSystemDialogs();
}
@Override
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 29680d8..302a530 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -138,6 +138,14 @@
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true" />
+ <activity android:name="com.android.systemui.activity.EmptyTestActivity"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<provider
android:name="androidx.startup.InitializationProvider"
tools:replace="android:authorities"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
index fbd2c91..8e81727 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
@@ -30,7 +30,6 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -126,13 +125,10 @@
@Test
fun sendCloseSystemDialogs_dispatchesWithWakelock() {
- val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
-
broadcastSender.closeSystemDialogs()
runExecutorAssertingWakelock {
- verify(mockContext).sendBroadcast(intentCaptor.capture())
- assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+ verify(mockContext).closeSystemDialogs()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
index 94cf384..9254617 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ClassifierTest.java
@@ -50,7 +50,7 @@
displayMetrics.widthPixels = 1000;
displayMetrics.heightPixels = 1000;
mDataProvider = new FalsingDataProvider(
- displayMetrics, mBatteryController, mFoldStateListener, mDockManager);
+ displayMetrics, mBatteryController, mFoldStateListener, mDockManager, false);
}
@After
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 8eadadf..7e06680 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -54,18 +54,18 @@
@Mock
private FoldStateListener mFoldStateListener;
private final DockManagerFake mDockManager = new DockManagerFake();
+ private DisplayMetrics mDisplayMetrics;
@Before
public void setup() {
super.setup();
MockitoAnnotations.initMocks(this);
- DisplayMetrics displayMetrics = new DisplayMetrics();
- displayMetrics.xdpi = 100;
- displayMetrics.ydpi = 100;
- displayMetrics.widthPixels = 1000;
- displayMetrics.heightPixels = 1000;
- mDataProvider = new FalsingDataProvider(
- displayMetrics, mBatteryController, mFoldStateListener, mDockManager);
+ mDisplayMetrics = new DisplayMetrics();
+ mDisplayMetrics.xdpi = 100;
+ mDisplayMetrics.ydpi = 100;
+ mDisplayMetrics.widthPixels = 1000;
+ mDisplayMetrics.heightPixels = 1000;
+ mDataProvider = createWithFoldCapability(false);
}
@After
@@ -345,20 +345,42 @@
}
@Test
- public void test_FoldedState_Folded() {
+ public void test_UnfoldedState_Folded() {
+ FalsingDataProvider falsingDataProvider = createWithFoldCapability(true);
when(mFoldStateListener.getFolded()).thenReturn(true);
- assertThat(mDataProvider.isUnfolded()).isFalse();
+ assertThat(falsingDataProvider.isUnfolded()).isFalse();
}
@Test
- public void test_FoldedState_Unfolded() {
+ public void test_UnfoldedState_Unfolded() {
+ FalsingDataProvider falsingDataProvider = createWithFoldCapability(true);
when(mFoldStateListener.getFolded()).thenReturn(false);
- assertThat(mDataProvider.isUnfolded()).isTrue();
+ assertThat(falsingDataProvider.isUnfolded()).isTrue();
}
@Test
- public void test_FoldedState_NotFoldable() {
+ public void test_Nonfoldabled_TrueFoldState() {
+ FalsingDataProvider falsingDataProvider = createWithFoldCapability(false);
+ when(mFoldStateListener.getFolded()).thenReturn(true);
+ assertThat(falsingDataProvider.isUnfolded()).isFalse();
+ }
+
+ @Test
+ public void test_Nonfoldabled_FalseFoldState() {
+ FalsingDataProvider falsingDataProvider = createWithFoldCapability(false);
+ when(mFoldStateListener.getFolded()).thenReturn(false);
+ assertThat(falsingDataProvider.isUnfolded()).isFalse();
+ }
+
+ @Test
+ public void test_Nonfoldabled_NullFoldState() {
+ FalsingDataProvider falsingDataProvider = createWithFoldCapability(true);
when(mFoldStateListener.getFolded()).thenReturn(null);
- assertThat(mDataProvider.isUnfolded()).isFalse();
+ assertThat(falsingDataProvider.isUnfolded()).isFalse();
+ }
+
+ private FalsingDataProvider createWithFoldCapability(boolean foldable) {
+ return new FalsingDataProvider(
+ mDisplayMetrics, mBatteryController, mFoldStateListener, mDockManager, foldable);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt
new file mode 100644
index 0000000..86e2bd3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsPopupMenuTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.app.Activity
+import android.graphics.Color
+import android.graphics.drawable.ShapeDrawable
+import android.testing.AndroidTestingRunner
+import android.util.DisplayMetrics
+import android.view.View
+import android.widget.PopupWindow.OnDismissListener
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.EmptyTestActivity
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+open class ControlsPopupMenuTest : SysuiTestCase() {
+
+ private companion object {
+
+ const val DISPLAY_WIDTH_NARROW = 100
+ const val DISPLAY_WIDTH_WIDE = 1000
+
+ const val MAX_WIDTH = 380
+ const val HORIZONTAL_MARGIN = 16
+ }
+
+ @Rule @JvmField val activityScenarioRule = ActivityScenarioRule(EmptyTestActivity::class.java)
+
+ private val testDisplayMetrics: DisplayMetrics = DisplayMetrics()
+
+ @Test
+ fun testDismissListenerWorks() = testPopup { popupMenu ->
+ val listener = mock(OnDismissListener::class.java)
+ popupMenu.setOnDismissListener(listener)
+ popupMenu.show()
+
+ popupMenu.dismissImmediate()
+
+ verify(listener).onDismiss()
+ }
+
+ @Test
+ fun testPopupDoesntExceedMaxWidth() = testPopup { popupMenu ->
+ testDisplayMetrics.widthPixels = DISPLAY_WIDTH_WIDE
+
+ popupMenu.show()
+
+ assertThat(popupMenu.width).isEqualTo(MAX_WIDTH)
+ }
+
+ @Test
+ fun testPopupMarginsWidthLessMax() = testPopup { popupMenu ->
+ testDisplayMetrics.widthPixels = DISPLAY_WIDTH_NARROW
+
+ popupMenu.show()
+
+ assertThat(popupMenu.width).isEqualTo(DISPLAY_WIDTH_NARROW - 2 * HORIZONTAL_MARGIN)
+ }
+
+ private fun testPopup(test: (popup: ControlsPopupMenu) -> Unit) {
+ activityScenarioRule.scenario.onActivity { activity ->
+ val testActivity = setupActivity(activity)
+ test(ControlsPopupMenu(testActivity).apply { anchorView = View(testActivity) })
+ }
+ }
+
+ private fun setupActivity(real: Activity): Activity {
+ val resources =
+ spy(real.resources).apply {
+ whenever(getDimensionPixelSize(R.dimen.control_popup_items_divider_height))
+ .thenReturn(1)
+ whenever(getDimensionPixelSize(R.dimen.control_popup_horizontal_margin))
+ .thenReturn(HORIZONTAL_MARGIN)
+ whenever(getDimensionPixelSize(R.dimen.control_popup_max_width))
+ .thenReturn(MAX_WIDTH)
+ whenever(getDrawable(R.drawable.controls_popup_bg)).thenReturn(ShapeDrawable())
+ whenever(getColor(R.color.control_popup_dim)).thenReturn(Color.WHITE)
+ whenever(displayMetrics).thenAnswer { testDisplayMetrics }
+ }
+
+ return spy(real).also { whenever(it.resources).thenReturn(resources) }
+ }
+}
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
index 330a1e4..84584807 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -234,7 +234,7 @@
val serviceInfo2 = setUpPanel(panel2)
`when`(authorizedPanelsRepository.getAuthorizedPanels())
- .thenReturn(setOf(packageName1, packageName2))
+ .thenReturn(setOf(packageName1, packageName2))
underTest.show(parent, {}, context)
@@ -245,7 +245,7 @@
captor.value.onServicesUpdated(listOf(serviceInfo1, serviceInfo2))
FakeExecutor.exhaustExecutors(uiExecutor, bgExecutor)
- val header: View = parent.requireViewById(R.id.controls_header)
+ val header: View = parent.requireViewById(R.id.app_or_structure_spinner)
assertThat(header.isClickable).isTrue()
assertThat(header.hasOnClickListeners()).isTrue()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 2ab1b99..9cd2220 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -125,4 +125,26 @@
assertThat(sideFpsIsShowing).isEqualTo(true)
job.cancel()
}
+
+ @Test
+ fun isShowing() = runTest {
+ var isShowing: Boolean? = null
+ val job = underTest.isShowing.onEach { isShowing = it }.launchIn(this)
+ repository.setPrimaryShow(true)
+ // Run the tasks that are pending at this point of virtual time.
+ runCurrent()
+ assertThat(isShowing).isEqualTo(true)
+ job.cancel()
+ }
+
+ @Test
+ fun isNotShowing() = runTest {
+ var isShowing: Boolean? = null
+ val job = underTest.isShowing.onEach { isShowing = it }.launchIn(this)
+ repository.setPrimaryShow(false)
+ // Run the tasks that are pending at this point of virtual time.
+ runCurrent()
+ assertThat(isShowing).isEqualTo(false)
+ job.cancel()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
index d364f47..fb5197e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/DynamicColorTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertTrue;
+
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -178,12 +179,39 @@
}
}
+ @Test
+ public void valuesAreCorrect() {
+ // Checks that the values of certain dynamic colors match Dart results.
+ assertThat(
+ MaterialDynamicColors.onPrimaryContainer.getArgb(
+ new SchemeFidelity(Hct.fromInt(0xFFFF0000), false, 0.5)))
+ .isSameColorAs(0xFFFFE5E1);
+ assertThat(
+ MaterialDynamicColors.onSecondaryContainer.getArgb(
+ new SchemeContent(Hct.fromInt(0xFF0000FF), false, 0.5)))
+ .isSameColorAs(0xFFFFFCFF);
+ assertThat(
+ MaterialDynamicColors.onTertiaryContainer.getArgb(
+ new SchemeContent(Hct.fromInt(0xFFFFFF00), true, -0.5)))
+ .isSameColorAs(0xFF616600);
+ assertThat(
+ MaterialDynamicColors.surfaceInverse.getArgb(
+ new SchemeContent(Hct.fromInt(0xFF0000FF), false, 0.0)))
+ .isSameColorAs(0xFF464652);
+ assertThat(
+ MaterialDynamicColors.primaryInverse.getArgb(
+ new SchemeContent(Hct.fromInt(0xFFFF0000), false, -0.5)))
+ .isSameColorAs(0xFFFF8C7A);
+ assertThat(
+ MaterialDynamicColors.outlineVariant.getArgb(
+ new SchemeContent(Hct.fromInt(0xFFFFFF00), true, 0.0)))
+ .isSameColorAs(0xFF484831);
+ }
+
private boolean pairSatisfiesContrast(DynamicScheme scheme, DynamicColor fg, DynamicColor bg) {
double fgTone = fg.getHct(scheme).getTone();
double bgTone = bg.getHct(scheme).getTone();
- // TODO(b/270915664) - Fix inconsistencies.
- // TODO(b/270915664) - Minimum requirement should be 4.5 when not reducing contrast.
- double minimumRequirement = 3.0;
+ double minimumRequirement = scheme.contrastLevel >= 0.0 ? 4.5 : 3.0;
return Contrast.ratioOfTones(fgTone, bgTone) >= minimumRequirement;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index e640946..6543bcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.notetask
+import android.app.ActivityManager
import android.app.KeyguardManager
import android.app.admin.DevicePolicyManager
import android.app.role.RoleManager
@@ -69,26 +70,27 @@
@RunWith(AndroidJUnit4::class)
internal class NoteTaskControllerTest : SysuiTestCase() {
- @Mock lateinit var context: Context
- @Mock lateinit var packageManager: PackageManager
- @Mock lateinit var resolver: NoteTaskInfoResolver
- @Mock lateinit var bubbles: Bubbles
- @Mock lateinit var keyguardManager: KeyguardManager
- @Mock lateinit var userManager: UserManager
- @Mock lateinit var eventLogger: NoteTaskEventLogger
- @Mock lateinit var roleManager: RoleManager
- @Mock lateinit var shortcutManager: ShortcutManager
+ @Mock private lateinit var context: Context
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var resolver: NoteTaskInfoResolver
+ @Mock private lateinit var bubbles: Bubbles
+ @Mock private lateinit var keyguardManager: KeyguardManager
+ @Mock private lateinit var userManager: UserManager
+ @Mock private lateinit var eventLogger: NoteTaskEventLogger
+ @Mock private lateinit var roleManager: RoleManager
+ @Mock private lateinit var shortcutManager: ShortcutManager
+ @Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
private val userTracker: UserTracker = FakeUserTracker()
- private val noteTaskInfo = NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID)
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(context.getString(R.string.note_task_button_label)).thenReturn(NOTES_SHORT_LABEL)
+ whenever(context.getString(R.string.note_task_button_label))
+ .thenReturn(NOTE_TASK_SHORT_LABEL)
whenever(context.packageManager).thenReturn(packageManager)
- whenever(resolver.resolveInfo(any(), any())).thenReturn(noteTaskInfo)
+ whenever(resolver.resolveInfo(any(), any())).thenReturn(NOTE_TASK_INFO)
whenever(userManager.isUserUnlocked).thenReturn(true)
whenever(
devicePolicyManager.getKeyguardDisabledFeatures(
@@ -98,7 +100,8 @@
)
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE)
whenever(roleManager.getRoleHoldersAsUser(ROLE_NOTES, userTracker.userHandle))
- .thenReturn(listOf(NOTES_PACKAGE_NAME))
+ .thenReturn(listOf(NOTE_TASK_PACKAGE_NAME))
+ whenever(activityManager.getRunningTasks(anyInt())).thenReturn(emptyList())
}
private fun createNoteTaskController(
@@ -117,12 +120,13 @@
userTracker = userTracker,
roleManager = roleManager,
shortcutManager = shortcutManager,
+ activityManager = activityManager,
)
// region onBubbleExpandChanged
@Test
fun onBubbleExpandChanged_expanding_logNoteTaskOpened() {
- val expectedInfo = noteTaskInfo.copy(isKeyguardLocked = false)
+ val expectedInfo = NOTE_TASK_INFO.copy(isKeyguardLocked = false)
createNoteTaskController()
.apply { infoReference.set(expectedInfo) }
@@ -137,7 +141,7 @@
@Test
fun onBubbleExpandChanged_collapsing_logNoteTaskClosed() {
- val expectedInfo = noteTaskInfo.copy(isKeyguardLocked = false)
+ val expectedInfo = NOTE_TASK_INFO.copy(isKeyguardLocked = false)
createNoteTaskController()
.apply { infoReference.set(expectedInfo) }
@@ -152,7 +156,7 @@
@Test
fun onBubbleExpandChanged_expandingAndKeyguardLocked_shouldDoNothing() {
- val expectedInfo = noteTaskInfo.copy(isKeyguardLocked = true)
+ val expectedInfo = NOTE_TASK_INFO.copy(isKeyguardLocked = true)
createNoteTaskController()
.apply { infoReference.set(expectedInfo) }
@@ -166,7 +170,7 @@
@Test
fun onBubbleExpandChanged_notExpandingAndKeyguardLocked_shouldDoNothing() {
- val expectedInfo = noteTaskInfo.copy(isKeyguardLocked = true)
+ val expectedInfo = NOTE_TASK_INFO.copy(isKeyguardLocked = true)
createNoteTaskController()
.apply { infoReference.set(expectedInfo) }
@@ -205,7 +209,7 @@
@Test
fun showNoteTask_keyguardIsLocked_shouldStartActivityAndLogUiEvent() {
val expectedInfo =
- noteTaskInfo.copy(
+ NOTE_TASK_INFO.copy(
entryPoint = NoteTaskEntryPoint.TAIL_BUTTON,
isKeyguardLocked = true,
)
@@ -222,7 +226,7 @@
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
- assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
+ assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags and FLAG_ACTIVITY_NEW_TASK).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.flags and FLAG_ACTIVITY_MULTIPLE_TASK)
.isEqualTo(FLAG_ACTIVITY_MULTIPLE_TASK)
@@ -239,7 +243,7 @@
fun showNoteTaskWithUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() {
val user10 = UserHandle.of(/* userId= */ 10)
val expectedInfo =
- noteTaskInfo.copy(
+ NOTE_TASK_INFO.copy(
entryPoint = NoteTaskEntryPoint.TAIL_BUTTON,
isKeyguardLocked = true,
)
@@ -257,7 +261,7 @@
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
- assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
+ assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags and FLAG_ACTIVITY_NEW_TASK).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.flags and FLAG_ACTIVITY_MULTIPLE_TASK)
.isEqualTo(FLAG_ACTIVITY_MULTIPLE_TASK)
@@ -271,9 +275,27 @@
}
@Test
+ fun showNoteTask_keyguardIsLocked_noteIsOpen_shouldStartActivityAndLogUiEvent() {
+ val expectedInfo =
+ NOTE_TASK_INFO.copy(
+ entryPoint = NoteTaskEntryPoint.TAIL_BUTTON,
+ isKeyguardLocked = true,
+ )
+ whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
+ whenever(resolver.resolveInfo(any(), any())).thenReturn(expectedInfo)
+ whenever(activityManager.getRunningTasks(anyInt()))
+ .thenReturn(listOf(NOTE_RUNNING_TASK_INFO))
+
+ createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
+
+ verify(context, never()).startActivityAsUser(any(), any())
+ verifyZeroInteractions(bubbles, eventLogger)
+ }
+
+ @Test
fun showNoteTask_keyguardIsUnlocked_shouldStartBubblesWithoutLoggingUiEvent() {
val expectedInfo =
- noteTaskInfo.copy(
+ NOTE_TASK_INFO.copy(
entryPoint = NoteTaskEntryPoint.TAIL_BUTTON,
isKeyguardLocked = false,
)
@@ -291,7 +313,7 @@
.showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle), isNull())
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
- assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
+ assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
}
@@ -426,7 +448,7 @@
.showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle), isNull())
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
- assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
+ assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
}
@@ -450,7 +472,7 @@
.showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle), isNull())
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
- assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
+ assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
}
@@ -480,11 +502,11 @@
assertThat(actualShortcut.intent?.component?.className)
.isEqualTo(LaunchNoteTaskActivity::class.java.name)
assertThat(actualShortcut.intent?.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
- assertThat(actualShortcut.shortLabel).isEqualTo(NOTES_SHORT_LABEL)
+ assertThat(actualShortcut.shortLabel).isEqualTo(NOTE_TASK_SHORT_LABEL)
assertThat(actualShortcut.isLongLived).isEqualTo(true)
assertThat(actualShortcut.icon.resId).isEqualTo(R.drawable.ic_note_task_shortcut_widget)
assertThat(actualShortcut.extras?.getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE))
- .isEqualTo(NOTES_PACKAGE_NAME)
+ .isEqualTo(NOTE_TASK_PACKAGE_NAME)
}
@Test
@@ -528,8 +550,19 @@
// endregion
private companion object {
- const val NOTES_SHORT_LABEL = "Notetaking"
- const val NOTES_PACKAGE_NAME = "com.android.note.app"
- const val NOTES_UID = 123456
+ const val NOTE_TASK_SHORT_LABEL = "Notetaking"
+ const val NOTE_TASK_ACTIVITY_NAME = "NoteTaskActivity"
+ const val NOTE_TASK_PACKAGE_NAME = "com.android.note.app"
+ const val NOTE_TASK_UID = 123456
+
+ private val NOTE_TASK_INFO =
+ NoteTaskInfo(
+ packageName = NOTE_TASK_PACKAGE_NAME,
+ uid = NOTE_TASK_UID,
+ )
+ private val NOTE_RUNNING_TASK_INFO =
+ ActivityManager.RunningTaskInfo().apply {
+ topActivity = ComponentName(NOTE_TASK_PACKAGE_NAME, NOTE_TASK_ACTIVITY_NAME)
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index d44012f..42ef2b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -19,6 +19,7 @@
package com.android.systemui.notetask.quickaffordance
import android.hardware.input.InputSettings
+import android.os.UserManager
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.dx.mockito.inline.extended.ExtendedMockito
@@ -33,6 +34,7 @@
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
import com.android.systemui.stylus.StylusManager
+import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -55,6 +57,7 @@
@Mock lateinit var controller: NoteTaskController
@Mock lateinit var stylusManager: StylusManager
@Mock lateinit var repository: KeyguardQuickAffordanceRepository
+ @Mock lateinit var userManager: UserManager
private lateinit var mockitoSession: MockitoSession
@@ -66,12 +69,6 @@
.mockStatic(InputSettings::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
-
- whenever(InputSettings.isStylusEverUsed(mContext)).then { true }
- whenever(repository.selections).then {
- val map = mapOf("" to listOf(createUnderTest()))
- MutableStateFlow(map)
- }
}
@After
@@ -84,6 +81,8 @@
context = context,
controller = controller,
stylusManager = stylusManager,
+ userManager = userManager,
+ keyguardMonitor = mock(),
lazyRepository = { repository },
isEnabled = isEnabled,
)
@@ -98,47 +97,101 @@
)
)
+ // region lockScreenState
@Test
- fun lockScreenState_stylusUsed_noCustomShortcutSelected_shouldEmitVisible() = runTest {
- val underTest = createUnderTest()
+ fun lockScreenState_stylusUsed_userUnlocked_isSelected_shouldEmitVisible() = runTest {
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(true)
+ .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
+ val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(createLockScreenStateVisible())
}
@Test
- fun lockScreenState_noStylusEverUsed_noCustomShortcutSelected_shouldEmitVisible() = runTest {
- whenever(InputSettings.isStylusEverUsed(mContext)).then { false }
- val underTest = createUnderTest()
+ fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
+ TestConfig()
+ .setStylusEverUsed(false)
+ .setUserUnlocked(true)
+ .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
+ val underTest = createUnderTest()
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Test
+ fun lockScreenState_stylusUsed_userLocked_isSelected_shouldEmitHidden() = runTest {
+ TestConfig()
+ .setStylusEverUsed(true)
+ .setUserUnlocked(false)
+ .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
+
+ val underTest = createUnderTest()
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Test
+ fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitVisible() = runTest {
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
+
+ val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(createLockScreenStateVisible())
}
@Test
- fun lockScreenState_stylusUsed_customShortcutSelected_shouldEmitVisible() = runTest {
- whenever(repository.selections).then {
- val map = mapOf<String, List<KeyguardQuickAffordanceConfig>>()
- MutableStateFlow(map)
- }
- val underTest = createUnderTest()
+ fun lockScreenState_stylusUnused_userUnlocked_noSelected_shouldEmitHidden() = runTest {
+ TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections()
+ val underTest = createUnderTest()
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Test
+ fun lockScreenState_stylusUsed_userLocked_noSelected_shouldEmitHidden() = runTest {
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections()
+
+ val underTest = createUnderTest()
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Test
+ fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitVisible() = runTest {
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(mock())
+
+ val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(createLockScreenStateVisible())
}
@Test
- fun lockScreenState_noIsStylusEverUsed_noCustomShortcutSelected_shouldEmitHidden() = runTest {
- whenever(InputSettings.isStylusEverUsed(mContext)).then { false }
- whenever(repository.selections).then {
- val map = mapOf<String, List<KeyguardQuickAffordanceConfig>>()
- MutableStateFlow(map)
- }
- val underTest = createUnderTest()
+ fun lockScreenState_stylusUnused_userUnlocked_customSelections_shouldEmitHidden() = runTest {
+ TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(mock())
+ val underTest = createUnderTest()
+ val actual by collectLastValue(underTest.lockScreenState)
+
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
+ }
+
+ @Test
+ fun lockScreenState_stylusUsed_userLocked_customSelections_shouldEmitHidden() = runTest {
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(mock())
+
+ val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
@@ -146,12 +199,14 @@
@Test
fun lockScreenState_isNotEnabled_shouldEmitHidden() = runTest {
- val underTest = createUnderTest(isEnabled = false)
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
+ val underTest = createUnderTest(isEnabled = false)
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
+ // endregion
@Test
fun onTriggered_shouldLaunchNoteTask() {
@@ -161,4 +216,22 @@
verify(controller).showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
}
+
+ private inner class TestConfig {
+
+ fun setStylusEverUsed(value: Boolean) = also {
+ whenever(InputSettings.isStylusEverUsed(mContext)).thenReturn(value)
+ }
+
+ fun setUserUnlocked(value: Boolean) = also {
+ whenever(userManager.isUserUnlocked).thenReturn(value)
+ }
+
+ fun setConfigSelections(vararg values: KeyguardQuickAffordanceConfig) = also {
+ val slotKey = "bottom-right"
+ val configSnapshots = values.toList()
+ val map = mapOf(slotKey to configSnapshots)
+ whenever(repository.selections).thenReturn(MutableStateFlow(map))
+ }
+ }
}
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 df3a62f..197b5970 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
@@ -45,7 +45,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.google.common.util.concurrent.ListenableFuture;
@@ -110,7 +109,6 @@
@Test
public void testImageExport() throws ExecutionException, InterruptedException, IOException {
ContentResolver contentResolver = mContext.getContentResolver();
- mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true);
ImageExporter exporter = new ImageExporter(contentResolver, mFeatureFlags);
UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
@@ -189,7 +187,6 @@
@Test
public void testSetUser() {
- mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true);
ImageExporter exporter = new ImageExporter(mMockContentResolver, mFeatureFlags);
UserHandle imageUserHande = UserHandle.of(10);
@@ -207,24 +204,6 @@
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/MessageContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
index 9f0a803..d672056 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/MessageContainerControllerTest.kt
@@ -83,7 +83,6 @@
@Test
fun testOnScreenshotTakenUserHandle_noWorkProfileFirstRun() {
- featureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
// (just being explicit here)
whenever(workProfileMessageController.onScreenshotTaken(eq(userHandle))).thenReturn(null)
@@ -93,18 +92,7 @@
}
@Test
- fun testOnScreenshotTakenUserHandle_noWorkProfileFlag() {
- featureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
-
- messageContainer.onScreenshotTaken(userHandle)
-
- verify(workProfileMessageController, never()).onScreenshotTaken(any())
- verify(workProfileMessageController, never()).populateView(any(), any(), any())
- }
-
- @Test
fun testOnScreenshotTakenUserHandle_withWorkProfileFirstRun() {
- featureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
whenever(workProfileMessageController.onScreenshotTaken(eq(userHandle)))
.thenReturn(workProfileData)
messageContainer.onScreenshotTaken(userHandle)
@@ -116,21 +104,7 @@
}
@Test
- fun testOnScreenshotTakenScreenshotData_flagsOff() {
- featureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
- featureFlags.set(Flags.SCREENSHOT_DETECTION, false)
-
- messageContainer.onScreenshotTaken(screenshotData)
-
- verify(workProfileMessageController, never()).onScreenshotTaken(any())
- verify(screenshotDetectionController, never()).maybeNotifyOfScreenshot(any())
-
- assertEquals(View.GONE, container.visibility)
- }
-
- @Test
fun testOnScreenshotTakenScreenshotData_nothingToShow() {
- featureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
featureFlags.set(Flags.SCREENSHOT_DETECTION, true)
messageContainer.onScreenshotTaken(screenshotData)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
index 2e73c0b5..1e47f78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -29,7 +29,6 @@
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import com.android.internal.util.ScreenshotRequest
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
@@ -53,10 +52,10 @@
/** Tests the Java-compatible function wrapper, ensures callback is invoked. */
@Test
fun testProcessAsync() {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
-
val request =
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER).build()
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_KEY_OTHER)
+ .setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
+ .build()
val processor = RequestProcessor(imageCapture, policy, flags, scope)
var result: ScreenshotRequest? = null
@@ -77,11 +76,11 @@
/** Tests the Java-compatible function wrapper, ensures callback is invoked. */
@Test
fun testProcessAsync_ScreenshotData() {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
-
val request =
ScreenshotData.fromRequest(
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER).build()
+ ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_KEY_OTHER)
+ .setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
+ .build()
)
val processor = RequestProcessor(imageCapture, policy, flags, scope)
@@ -101,28 +100,7 @@
}
@Test
- fun testFullScreenshot_workProfilePolicyDisabled() = runBlocking {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
-
- val request =
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER).build()
- val processor = RequestProcessor(imageCapture, policy, flags, scope)
-
- val processedRequest = processor.process(request)
-
- // No changes
- assertThat(processedRequest).isEqualTo(request)
-
- val screenshotData = ScreenshotData.fromRequest(request)
- val processedData = processor.process(screenshotData)
-
- assertThat(processedData).isEqualTo(screenshotData)
- }
-
- @Test
fun testFullScreenshot() = runBlocking {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
-
// Indicate that the primary content belongs to a normal user
policy.setManagedProfile(USER_ID, false)
policy.setDisplayContentInfo(
@@ -151,8 +129,6 @@
@Test
fun testFullScreenshot_managedProfile() = runBlocking {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
-
// Provide a fake task bitmap when asked
val bitmap = makeHardwareBitmap(100, 100)
imageCapture.image = bitmap
@@ -195,8 +171,6 @@
@Test
fun testFullScreenshot_managedProfile_nullBitmap() {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
-
// Provide a null task bitmap when asked
imageCapture.image = null
@@ -220,39 +194,7 @@
}
@Test
- fun testProvidedImageScreenshot_workProfilePolicyDisabled() = runBlocking {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
-
- val bounds = Rect(50, 50, 150, 150)
- val processor = RequestProcessor(imageCapture, policy, flags, scope)
-
- val bitmap = makeHardwareBitmap(100, 100)
-
- val request =
- ScreenshotRequest.Builder(TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_OTHER)
- .setTopComponent(component)
- .setTaskId(TASK_ID)
- .setUserId(USER_ID)
- .setBitmap(bitmap)
- .setBoundsOnScreen(bounds)
- .setInsets(Insets.NONE)
- .build()
-
- val processedRequest = processor.process(request)
-
- // No changes
- assertThat(processedRequest).isEqualTo(request)
-
- val screenshotData = ScreenshotData.fromRequest(request)
- val processedData = processor.process(screenshotData)
-
- assertThat(processedData).isEqualTo(screenshotData)
- }
-
- @Test
fun testProvidedImageScreenshot() = runBlocking {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
-
val bounds = Rect(50, 50, 150, 150)
val processor = RequestProcessor(imageCapture, policy, flags, scope)
@@ -283,8 +225,6 @@
@Test
fun testProvidedImageScreenshot_managedProfile() = runBlocking {
- flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
-
val bounds = Rect(50, 50, 150, 150)
val processor = RequestProcessor(imageCapture, policy, flags, scope)
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 c40c287..47d88a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -39,7 +39,6 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags.SCREENSHOT_METADATA_REFACTOR
-import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER
import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW
@@ -125,7 +124,6 @@
.processAsync(/* screenshot= */ any(ScreenshotData::class.java), /* callback= */ any())
// Flipped in selected test cases
- flags.set(SCREENSHOT_WORK_PROFILE_POLICY, false)
flags.set(SCREENSHOT_METADATA_REFACTOR, false)
service.attach(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
index b527861..9bd3a79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/WalletContextualSuggestionsControllerTest.kt
@@ -32,9 +32,9 @@
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import java.util.ArrayList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
@@ -46,7 +46,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.isNull
+import org.mockito.Mockito.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -66,12 +66,14 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
+ whenever(broadcastDispatcher.broadcastFlow(any(), nullable(), anyInt(), nullable()))
+ .thenCallRealMethod()
whenever(
- broadcastDispatcher.broadcastFlow<List<String>?>(
+ broadcastDispatcher.broadcastFlow<Unit>(
any(),
- isNull(),
- any(),
- any(),
+ nullable(),
+ anyInt(),
+ nullable(),
any()
)
)
@@ -81,95 +83,85 @@
.thenReturn(true)
whenever(CARD_1.cardId).thenReturn(ID_1)
+ whenever(CARD_1.cardType).thenReturn(WalletCard.CARD_TYPE_NON_PAYMENT)
whenever(CARD_2.cardId).thenReturn(ID_2)
+ whenever(CARD_2.cardType).thenReturn(WalletCard.CARD_TYPE_NON_PAYMENT)
whenever(CARD_3.cardId).thenReturn(ID_3)
+ whenever(CARD_3.cardType).thenReturn(WalletCard.CARD_TYPE_NON_PAYMENT)
+ whenever(PAYMENT_CARD.cardId).thenReturn(PAYMENT_ID)
+ whenever(PAYMENT_CARD.cardType).thenReturn(WalletCard.CARD_TYPE_PAYMENT)
}
@Test
- fun `state - has wallet cards - received contextual cards`() = runTest {
- setUpWalletClient(listOf(CARD_1, CARD_2))
- val latest =
- collectLastValue(
- createWalletContextualSuggestionsController(backgroundScope)
- .contextualSuggestionCards,
- )
+ fun `state - has wallet cards- callbacks called`() = runTest {
+ setUpWalletClient(listOf(CARD_1, CARD_2, PAYMENT_CARD))
+ val controller = createWalletContextualSuggestionsController(backgroundScope)
+ var latest1 = emptyList<WalletCard>()
+ var latest2 = emptyList<WalletCard>()
+ val callback1: (List<WalletCard>) -> Unit = { latest1 = it }
+ val callback2: (List<WalletCard>) -> Unit = { latest2 = it }
runCurrent()
- verifyRegistered()
- broadcastReceiver.value.onReceive(
- mockContext,
- createContextualCardsIntent(listOf(ID_1, ID_2))
- )
+ controller.registerWalletCardsReceivedCallback(callback1)
+ controller.registerWalletCardsReceivedCallback(callback2)
+ controller.unregisterWalletCardsReceivedCallback(callback2)
+ runCurrent()
+ verifyBroadcastReceiverRegistered()
+ turnScreenOn()
+ runCurrent()
- assertThat(latest()).containsExactly(CARD_1, CARD_2)
+ assertThat(latest1).containsExactly(CARD_1, CARD_2)
+ assertThat(latest2).isEmpty()
}
@Test
- fun `state - no wallet cards - received contextual cards`() = runTest {
+ fun `state - no wallet cards - set suggestion cards`() = runTest {
setUpWalletClient(emptyList())
+ val controller = createWalletContextualSuggestionsController(backgroundScope)
val latest =
collectLastValue(
- createWalletContextualSuggestionsController(backgroundScope)
- .contextualSuggestionCards,
+ controller.contextualSuggestionCards,
)
runCurrent()
- verifyRegistered()
- broadcastReceiver.value.onReceive(
- mockContext,
- createContextualCardsIntent(listOf(ID_1, ID_2))
- )
+ verifyBroadcastReceiverRegistered()
+ turnScreenOn()
+ controller.setSuggestionCardIds(setOf(ID_1, ID_2))
assertThat(latest()).isEmpty()
}
@Test
- fun `state - has wallet cards - no contextual cards`() = runTest {
- setUpWalletClient(listOf(CARD_1, CARD_2))
+ fun `state - has wallet cards - set and update suggestion cards`() = runTest {
+ setUpWalletClient(listOf(CARD_1, CARD_2, PAYMENT_CARD))
+ val controller = createWalletContextualSuggestionsController(backgroundScope)
val latest =
collectLastValue(
- createWalletContextualSuggestionsController(backgroundScope)
- .contextualSuggestionCards,
+ controller.contextualSuggestionCards,
)
runCurrent()
- verifyRegistered()
- broadcastReceiver.value.onReceive(mockContext, createContextualCardsIntent(emptyList()))
+ verifyBroadcastReceiverRegistered()
+ turnScreenOn()
+ controller.setSuggestionCardIds(setOf(ID_1, ID_2))
+ assertThat(latest()).containsExactly(CARD_1, CARD_2)
+ controller.setSuggestionCardIds(emptySet())
assertThat(latest()).isEmpty()
}
@Test
fun `state - wallet cards error`() = runTest {
setUpWalletClient(shouldFail = true)
+ val controller = createWalletContextualSuggestionsController(backgroundScope)
val latest =
collectLastValue(
- createWalletContextualSuggestionsController(backgroundScope)
- .contextualSuggestionCards,
+ controller.contextualSuggestionCards,
)
runCurrent()
- verifyRegistered()
- broadcastReceiver.value.onReceive(
- mockContext,
- createContextualCardsIntent(listOf(ID_1, ID_2))
- )
-
- assertThat(latest()).isEmpty()
- }
-
- @Test
- fun `state - no contextual cards extra`() = runTest {
- setUpWalletClient(listOf(CARD_1, CARD_2))
- val latest =
- collectLastValue(
- createWalletContextualSuggestionsController(backgroundScope)
- .contextualSuggestionCards,
- )
-
- runCurrent()
- verifyRegistered()
- broadcastReceiver.value.onReceive(mockContext, Intent(INTENT_NAME))
+ verifyBroadcastReceiverRegistered()
+ controller.setSuggestionCardIds(setOf(ID_1, ID_2))
assertThat(latest()).isEmpty()
}
@@ -178,16 +170,18 @@
fun `state - has wallet cards - received contextual cards - feature disabled`() = runTest {
whenever(featureFlags.isEnabled(eq(Flags.ENABLE_WALLET_CONTEXTUAL_LOYALTY_CARDS)))
.thenReturn(false)
- setUpWalletClient(listOf(CARD_1, CARD_2))
+ setUpWalletClient(listOf(CARD_1, CARD_2, PAYMENT_CARD))
+ val controller = createWalletContextualSuggestionsController(backgroundScope)
val latest =
collectLastValue(
- createWalletContextualSuggestionsController(backgroundScope)
- .contextualSuggestionCards,
+ controller.contextualSuggestionCards,
)
runCurrent()
- verify(broadcastDispatcher, never()).broadcastFlow(any(), isNull(), any(), any())
- assertThat(latest()).isNull()
+ verify(broadcastDispatcher, never()).broadcastFlow(any(), nullable(), anyInt(), nullable())
+ controller.setSuggestionCardIds(setOf(ID_1, ID_2))
+
+ assertThat(latest()).isEmpty()
}
private fun createWalletContextualSuggestionsController(
@@ -201,17 +195,20 @@
)
}
- private fun verifyRegistered() {
+ private fun verifyBroadcastReceiverRegistered() {
verify(broadcastDispatcher)
- .registerReceiver(capture(broadcastReceiver), any(), isNull(), isNull(), any(), any())
+ .registerReceiver(
+ capture(broadcastReceiver),
+ any(),
+ nullable(),
+ nullable(),
+ anyInt(),
+ nullable()
+ )
}
- private fun createContextualCardsIntent(
- ids: List<String> = emptyList(),
- ): Intent {
- val intent = Intent(INTENT_NAME)
- intent.putStringArrayListExtra("cardIds", ArrayList(ids))
- return intent
+ private fun turnScreenOn() {
+ broadcastReceiver.value.onReceive(mockContext, Intent(Intent.ACTION_SCREEN_ON))
}
private fun setUpWalletClient(
@@ -238,6 +235,7 @@
private val CARD_2: WalletCard = mock()
private const val ID_3: String = "789"
private val CARD_3: WalletCard = mock()
- private val INTENT_NAME: String = "WalletSuggestionsIntent"
+ private const val PAYMENT_ID: String = "payment"
+ private val PAYMENT_CARD: WalletCard = mock()
}
}
diff --git a/packages/SystemUI/tests/utils/AndroidManifest.xml b/packages/SystemUI/tests/utils/AndroidManifest.xml
deleted file mode 100644
index cbef5f6..0000000
--- a/packages/SystemUI/tests/utils/AndroidManifest.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.tests.utils">
-
-
-</manifest>
-
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/activity/EmptyTestActivity.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/EmptyTestActivity.kt
new file mode 100644
index 0000000..22ac3d72a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/EmptyTestActivity.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.activity
+
+import android.app.Activity
+
+/**
+ * This activity does nothing. You can use it with [ActivityScenario] or [ActivityScenarioRule] to
+ * run activity-independent tests
+ */
+class EmptyTestActivity : Activity()
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index 7df0d86..6d198de 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -104,8 +104,9 @@
}
final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
config.getType(), config.getName(),
- config.getVendor() == null ? "" : config.getVendor(), config.getFlags(),
- mRuntimeSensorCallback);
+ config.getVendor() == null ? "" : config.getVendor(), config.getMaximumRange(),
+ config.getResolution(), config.getPower(), config.getMinDelay(),
+ config.getMaxDelay(), config.getFlags(), mRuntimeSensorCallback);
if (handle <= 0) {
throw new SensorCreationException("Received an invalid virtual sensor handle.");
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 32c9a09..65c4d75 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8837,7 +8837,7 @@
try {
AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
- UserHandle.USER_SYSTEM);
+ UserHandle.USER_SYSTEM, "am");
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 7c84b72..d9ba845 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -66,6 +66,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.WakeLockStats;
import android.os.WorkSource;
@@ -140,6 +141,7 @@
BatteryStatsImpl.EnergyStatsRetriever,
Watchdog.Monitor {
static final String TAG = "BatteryStatsService";
+ static final String TRACE_TRACK_WAKEUP_REASON = "wakeup_reason";
static final boolean DBG = false;
private static final boolean BATTERY_USAGE_STORE_ENABLED = true;
@@ -2482,6 +2484,10 @@
while ((reason = waitWakeup()) != null) {
final long nowElapsed = SystemClock.elapsedRealtime();
final long nowUptime = SystemClock.uptimeMillis();
+
+ Trace.instantForTrack(Trace.TRACE_TAG_POWER, TRACE_TRACK_WAKEUP_REASON,
+ nowElapsed + " " + reason);
+
// Wait for the completion of pending works if there is any
awaitCompletion();
mCpuWakeupStats.noteWakeupTimeAndReason(nowElapsed, nowUptime, reason);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index fc22935..965a07b 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -157,10 +157,10 @@
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServiceManager;
import com.android.server.pm.PackageList;
+import com.android.server.pm.PackageManagerLocal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
-import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.component.ParsedAttribution;
import com.android.server.policy.AppOpsPolicy;
@@ -367,6 +367,9 @@
/** Package Manager internal. Access via {@link #getPackageManagerInternal()} */
private @Nullable PackageManagerInternal mPackageManagerInternal;
+ /** Package Manager local. Access via {@link #getPackageManagerLocal()} */
+ private @Nullable PackageManagerLocal mPackageManagerLocal;
+
/** User Manager internal. Access via {@link #getUserManagerInternal()} */
private @Nullable UserManagerInternal mUserManagerInternal;
@@ -1189,42 +1192,64 @@
/**
* Initialize uid state objects for state contained in the checking service.
*/
- private void initializeUidStates() {
+ @VisibleForTesting
+ void initializeUidStates() {
UserManagerInternal umi = getUserManagerInternal();
- int[] userIds = umi.getUserIds();
synchronized (this) {
- for (int i = 0; i < userIds.length; i++) {
- int userId = userIds[i];
- initializeUserUidStatesLocked(userId);
+ int[] userIds = umi.getUserIds();
+ try (PackageManagerLocal.UnfilteredSnapshot snapshot =
+ getPackageManagerLocal().withUnfilteredSnapshot()) {
+ Map<String, PackageState> packageStates = snapshot.getPackageStates();
+ for (int i = 0; i < userIds.length; i++) {
+ int userId = userIds[i];
+ initializeUserUidStatesLocked(userId, packageStates);
+ }
}
}
}
private void initializeUserUidStates(int userId) {
synchronized (this) {
- initializeUserUidStatesLocked(userId);
+ try (PackageManagerLocal.UnfilteredSnapshot snapshot =
+ getPackageManagerLocal().withUnfilteredSnapshot()) {
+ initializeUserUidStatesLocked(userId, snapshot.getPackageStates());
+ }
}
}
- private void initializeUserUidStatesLocked(int userId) {
- ArrayMap<String, ? extends PackageStateInternal> packageStates =
- getPackageManagerInternal().getPackageStates();
- for (int j = 0; j < packageStates.size(); j++) {
- PackageStateInternal packageState = packageStates.valueAt(j);
- int uid = UserHandle.getUid(userId, packageState.getAppId());
- UidState uidState = getUidStateLocked(uid, true);
- String packageName = packageStates.keyAt(j);
- Ops ops = new Ops(packageName, uidState);
- uidState.pkgOps.put(packageName, ops);
+ private void initializeUserUidStatesLocked(int userId, Map<String,
+ PackageState> packageStates) {
+ for (Map.Entry<String, PackageState> entry : packageStates.entrySet()) {
+ int appId = entry.getValue().getAppId();
+ String packageName = entry.getKey();
- SparseIntArray packageModes =
- mAppOpsCheckingService.getNonDefaultPackageModes(packageName, userId);
- for (int k = 0; k < packageModes.size(); k++) {
- int code = packageModes.get(k);
+ initializePackageUidStateLocked(userId, appId, packageName);
+ }
+ }
+
+ /*
+ Be careful not to clear any existing data; only want to add objects that don't already exist.
+ */
+ private void initializePackageUidStateLocked(int userId, int appId, String packageName) {
+ int uid = UserHandle.getUid(userId, appId);
+ UidState uidState = getUidStateLocked(uid, true);
+ Ops ops = uidState.pkgOps.get(packageName);
+ if (ops == null) {
+ ops = new Ops(packageName, uidState);
+ uidState.pkgOps.put(packageName, ops);
+ }
+
+ SparseIntArray packageModes =
+ mAppOpsCheckingService.getNonDefaultPackageModes(packageName, userId);
+ for (int k = 0; k < packageModes.size(); k++) {
+ int code = packageModes.keyAt(k);
+
+ if (ops.indexOfKey(code) < 0) {
ops.put(code, new Op(uidState, packageName, code, uid));
}
- uidState.evalForegroundOps();
}
+
+ uidState.evalForegroundOps();
}
/**
@@ -3649,6 +3674,20 @@
}
/**
+ * @return {@link PackageManagerLocal}
+ */
+ private @NonNull PackageManagerLocal getPackageManagerLocal() {
+ if (mPackageManagerLocal == null) {
+ mPackageManagerLocal = LocalManagerRegistry.getManager(PackageManagerLocal.class);
+ }
+ if (mPackageManagerLocal == null) {
+ throw new IllegalStateException("PackageManagerLocal not loaded");
+ }
+
+ return mPackageManagerLocal;
+ }
+
+ /**
* @return {@link UserManagerInternal}
*/
private @NonNull UserManagerInternal getUserManagerInternal() {
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 13e29a3..0189294 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -2643,7 +2643,15 @@
public void observe() {
StatusBarManagerInternal statusBar =
LocalServices.getService(StatusBarManagerInternal.class);
- if (statusBar != null) {
+ if (statusBar == null) {
+ return;
+ }
+
+ // Allow UDFPS vote by registering callback, only
+ // if the device is configured to not ignore UDFPS vote.
+ boolean ignoreUdfpsVote = mContext.getResources()
+ .getBoolean(R.bool.config_ignoreUdfpsVote);
+ if (!ignoreUdfpsVote) {
statusBar.setUdfpsRefreshRateCallback(this);
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 20ff51c..8c0e19d 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -63,6 +63,10 @@
// Time to allow the dream to perform an exit transition when waking up.
private static final int DREAM_FINISH_TIMEOUT = 5 * 1000;
+ // Extras used with ACTION_CLOSE_SYSTEM_DIALOGS broadcast
+ private static final String EXTRA_REASON_KEY = "reason";
+ private static final String EXTRA_REASON_VALUE = "dream";
+
private final Context mContext;
private final Handler mHandler;
private final Listener mListener;
@@ -77,6 +81,7 @@
private final Bundle mDreamingStartedStoppedOptions = createDreamingStartedStoppedOptions();
private final Intent mCloseNotificationShadeIntent;
+ private final Bundle mCloseNotificationShadeOptions;
private DreamRecord mCurrentDream;
@@ -96,7 +101,14 @@
mListener = listener;
mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
mCloseNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mCloseNotificationShadeIntent.putExtra("reason", "dream");
+ mCloseNotificationShadeIntent.putExtra(EXTRA_REASON_KEY, EXTRA_REASON_VALUE);
+ mCloseNotificationShadeIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mCloseNotificationShadeOptions = BroadcastOptions.makeBasic()
+ .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
+ .setDeliveryGroupMatchingKey(Intent.ACTION_CLOSE_SYSTEM_DIALOGS,
+ EXTRA_REASON_VALUE)
+ .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
+ .toBundle();
}
/**
@@ -149,7 +161,8 @@
Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
try {
// Close the notification shade. No need to send to all, but better to be explicit.
- mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL,
+ null /* receiverPermission */, mCloseNotificationShadeOptions);
Slog.i(TAG, "Starting dream: name=" + name
+ ", isPreviewMode=" + isPreviewMode + ", canDoze=" + canDoze
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 91f58db..35c70fb 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -22,6 +22,7 @@
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.input.InputManager;
+import android.hardware.input.InputManagerGlobal;
import android.hardware.tv.cec.V1_0.Result;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioManager;
@@ -827,7 +828,7 @@
KeyEvent.FLAG_FROM_SYSTEM,
InputDevice.SOURCE_HDMI,
null);
- InputManager.getInstance()
+ InputManagerGlobal.getInstance()
.injectInputEvent(keyEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
keyEvent.recycle();
}
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index 773dc68..5132591 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -42,6 +42,7 @@
import static java.util.Collections.unmodifiableMap;
import android.hardware.input.InputManager;
+import android.hardware.input.InputManagerGlobal;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.util.ArrayMap;
@@ -109,7 +110,7 @@
}
private void injectKeyEvent(KeyEvent event) {
- InputManager.getInstance().injectInputEvent(event,
+ InputManagerGlobal.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
@@ -178,7 +179,7 @@
pointerProperties, pointerCoords, DEFAULT_META_STATE, DEFAULT_BUTTON_STATE,
DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, getInputDeviceId(inputSource),
DEFAULT_EDGE_FLAGS, inputSource, displayId, DEFAULT_FLAGS);
- InputManager.getInstance().injectInputEvent(event,
+ InputManagerGlobal.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
@@ -530,7 +531,7 @@
}
private void injectKeyEventAsync(KeyEvent event) {
- InputManager.getInstance().injectInputEvent(event,
+ InputManagerGlobal.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java
index e1e3dd9..4033238 100644
--- a/services/core/java/com/android/server/input/KeyboardBacklightController.java
+++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java
@@ -344,7 +344,7 @@
throw new IllegalStateException("The calling process has no registered "
+ "KeyboardBacklightListener.");
}
- if (record.mListener != listener) {
+ if (record.mListener.asBinder() != listener.asBinder()) {
throw new IllegalStateException("The calling process has a different registered "
+ "KeyboardBacklightListener.");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d630ff4..2038e79 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3779,7 +3779,7 @@
}
private void setEnabledSettings(List<ComponentEnabledSetting> settings, int userId,
- String callingPackage) {
+ @NonNull String callingPackage) {
final int callingUid = Binder.getCallingUid();
// TODO: This method is not properly snapshotified beyond this call
final Computer preLockSnapshot = snapshotComputer();
@@ -4051,11 +4051,6 @@
boolean success = false;
if (!setting.isComponent()) {
// We're dealing with an application/package level state change
- if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
- || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
- // Don't care about who enables an app.
- callingPackage = null;
- }
pkgSetting.setEnabled(newState, userId, callingPackage);
if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DISABLED)
@@ -5814,21 +5809,28 @@
@Override
public void setComponentEnabledSetting(ComponentName componentName,
- int newState, int flags, int userId) {
+ int newState, int flags, int userId, String callingPackage) {
if (!mUserManager.exists(userId)) return;
+ if (callingPackage == null) {
+ callingPackage = Integer.toString(Binder.getCallingUid());
+ }
setEnabledSettings(List.of(new PackageManager.ComponentEnabledSetting(componentName, newState, flags)),
- userId, null /* callingPackage */);
+ userId, callingPackage);
}
@Override
- public void setComponentEnabledSettings(List<PackageManager.ComponentEnabledSetting> settings, int userId) {
+ public void setComponentEnabledSettings(
+ List<PackageManager.ComponentEnabledSetting> settings, int userId,
+ String callingPackage) {
if (!mUserManager.exists(userId)) return;
if (settings == null || settings.isEmpty()) {
throw new IllegalArgumentException("The list of enabled settings is empty");
}
-
- setEnabledSettings(settings, userId, null /* callingPackage */);
+ if (callingPackage == null) {
+ callingPackage = Integer.toString(Binder.getCallingUid());
+ }
+ setEnabledSettings(settings, userId, callingPackage);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 232ca45..cc60802 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2447,7 +2447,7 @@
mInterface.getApplicationEnabledSetting(pkg, translatedUserId)));
return 0;
} else {
- mInterface.setComponentEnabledSetting(cn, state, 0, translatedUserId);
+ mInterface.setComponentEnabledSetting(cn, state, 0, translatedUserId, "shell");
getOutPrintWriter().println("Component " + cn.toShortString() + " new state: "
+ enabledSettingToString(
mInterface.getComponentEnabledSetting(cn, translatedUserId)));
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 94a00d6e..02d13bc 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3947,14 +3947,15 @@
final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
if (enabledStr != null) {
try {
- packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */, null);
+ packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */,
+ "settings");
} catch (NumberFormatException e) {
if (enabledStr.equalsIgnoreCase("true")) {
- packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0, null);
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0, "settings");
} else if (enabledStr.equalsIgnoreCase("false")) {
- packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, "settings");
} else if (enabledStr.equalsIgnoreCase("default")) {
- packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, "settings");
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: package " + name
@@ -3963,7 +3964,7 @@
}
}
} else {
- packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
+ packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, "settings");
}
addInstallerPackageNames(installSource);
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 b05b662..d55fbc2 100644
--- a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
+++ b/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.os.Handler;
import android.os.HandlerExecutor;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.IndentingPrintWriter;
@@ -55,6 +56,7 @@
private static final String SUBSYSTEM_ALARM_STRING = "Alarm";
private static final String SUBSYSTEM_ALARM_WIFI = "Wifi";
+ private static final String TRACE_TRACK_WAKEUP_ATTRIBUTION = "wakeup_attribution";
@VisibleForTesting
static final long WAKEUP_REASON_HALF_WINDOW_MS = 500;
private static final long WAKEUP_WRITE_DELAY_MS = TimeUnit.MINUTES.toMillis(2);
@@ -94,13 +96,15 @@
return FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__UNKNOWN;
}
- private synchronized void logWakeupToStatsLog(Wakeup wakeupToLog) {
+ private synchronized void logWakeupAttribution(Wakeup wakeupToLog) {
if (ArrayUtils.isEmpty(wakeupToLog.mDevices)) {
FrameworkStatsLog.write(FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED,
FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__TYPE__TYPE_UNKNOWN,
FrameworkStatsLog.KERNEL_WAKEUP_ATTRIBUTED__REASON__UNKNOWN,
null,
wakeupToLog.mElapsedMillis);
+ Trace.instantForTrack(Trace.TRACE_TAG_POWER, TRACE_TRACK_WAKEUP_ATTRIBUTION,
+ wakeupToLog.mElapsedMillis + " --");
return;
}
@@ -112,6 +116,9 @@
Slog.wtf(TAG, "Unexpected null attribution found for " + wakeupToLog);
return;
}
+
+ final StringBuilder traceEventBuilder = new StringBuilder();
+
for (int i = 0; i < wakeupAttribution.size(); i++) {
final int subsystem = wakeupAttribution.keyAt(i);
final SparseBooleanArray uidMap = wakeupAttribution.valueAt(i);
@@ -132,7 +139,19 @@
subsystemToStatsReason(subsystem),
uids,
wakeupToLog.mElapsedMillis);
+
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_POWER)) {
+ if (i == 0) {
+ traceEventBuilder.append(wakeupToLog.mElapsedMillis + " ");
+ }
+ traceEventBuilder.append((subsystemToString(subsystem)));
+ traceEventBuilder.append(":");
+ traceEventBuilder.append(Arrays.toString(uids));
+ traceEventBuilder.append(" ");
+ }
}
+ Trace.instantForTrack(Trace.TRACE_TAG_POWER, TRACE_TRACK_WAKEUP_ATTRIBUTION,
+ traceEventBuilder.toString().trim());
}
/** Notes a wakeup reason as reported by SuspendControlService to battery stats. */
@@ -160,7 +179,7 @@
for (int i = lastIdx; i >= 0; i--) {
mWakeupAttribution.removeAt(i);
}
- mHandler.postDelayed(() -> logWakeupToStatsLog(parsedWakeup), WAKEUP_WRITE_DELAY_MS);
+ mHandler.postDelayed(() -> logWakeupAttribution(parsedWakeup), WAKEUP_WRITE_DELAY_MS);
}
/** Notes a waking activity that could have potentially woken up the CPU. */
diff --git a/services/core/java/com/android/server/sensors/SensorManagerInternal.java b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
index 6c32ec2..7ff4ade 100644
--- a/services/core/java/com/android/server/sensors/SensorManagerInternal.java
+++ b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
@@ -60,7 +60,8 @@
* @return The sensor handle.
*/
public abstract int createRuntimeSensor(int deviceId, int type, @NonNull String name,
- @NonNull String vendor, int flags, @NonNull RuntimeSensorCallback callback);
+ @NonNull String vendor, float maximumRange, float resolution, float power,
+ int minDelay, int maxDelay, int flags, @NonNull RuntimeSensorCallback callback);
/**
* Unregisters the sensor with the given handle from the framework.
diff --git a/services/core/java/com/android/server/sensors/SensorService.java b/services/core/java/com/android/server/sensors/SensorService.java
index 1baa0a6..3de1910 100644
--- a/services/core/java/com/android/server/sensors/SensorService.java
+++ b/services/core/java/com/android/server/sensors/SensorService.java
@@ -56,7 +56,8 @@
private static native void unregisterProximityActiveListenerNative(long ptr);
private static native int registerRuntimeSensorNative(long ptr, int deviceId, int type,
- String name, String vendor, int flags,
+ String name, String vendor, float maximumRange, float resolution, float power,
+ int minDelay, int maxDelay, int flags,
SensorManagerInternal.RuntimeSensorCallback callback);
private static native void unregisterRuntimeSensorNative(long ptr, int handle);
private static native boolean sendRuntimeSensorEventNative(long ptr, int handle, int type,
@@ -96,10 +97,11 @@
class LocalService extends SensorManagerInternal {
@Override
public int createRuntimeSensor(int deviceId, int type, @NonNull String name,
- @NonNull String vendor, int flags, @NonNull RuntimeSensorCallback callback) {
+ @NonNull String vendor, float maximumRange, float resolution, float power,
+ int minDelay, int maxDelay, int flags, @NonNull RuntimeSensorCallback callback) {
synchronized (mLock) {
- int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor, flags,
- callback);
+ int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor,
+ maximumRange, resolution, power, minDelay, maxDelay, flags, callback);
mRuntimeSensorHandles.add(handle);
return handle;
}
diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java
index 28d34c2..2049a02 100644
--- a/services/core/java/com/android/server/timedetector/ServerFlags.java
+++ b/services/core/java/com/android/server/timedetector/ServerFlags.java
@@ -69,6 +69,7 @@
KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE,
+ KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT,
KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED,
KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
})
@@ -154,6 +155,14 @@
"location_time_zone_detection_setting_enabled_default";
/**
+ * The key to alter a device's "automatic time zone detection enabled" setting default value.
+ * This flag is only intended for internal testing.
+ */
+ public static final @DeviceConfigKey String
+ KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT =
+ "time_zone_detector_auto_detection_enabled_default";
+
+ /**
* The key to control support for time zone detection falling back to telephony detection under
* certain circumstances.
*/
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
index 6ebaf14c..a71f9c7 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
@@ -64,6 +64,7 @@
ServerFlags.KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
+ ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT,
ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED
);
@@ -174,7 +175,7 @@
}
}, filter, null, null /* main thread */);
- // Add async callbacks for global settings being changed.
+ // Add async callbacks for changes to global settings that influence behavior.
ContentResolver contentResolver = mContext.getContentResolver();
ContentObserver contentObserver = new ContentObserver(mContext.getMainThreadHandler()) {
@Override
@@ -184,6 +185,9 @@
};
contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, contentObserver);
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE_EXPLICIT), true,
+ contentObserver);
// Add async callbacks for user scoped location settings being changed.
contentResolver.registerContentObserver(
@@ -239,8 +243,9 @@
@Override
public synchronized boolean updateConfiguration(@UserIdInt int userId,
- @NonNull TimeZoneConfiguration requestedConfiguration, boolean bypassUserPolicyChecks) {
- Objects.requireNonNull(requestedConfiguration);
+ @NonNull TimeZoneConfiguration requestedConfigurationUpdates,
+ boolean bypassUserPolicyChecks) {
+ Objects.requireNonNull(requestedConfigurationUpdates);
ConfigurationInternal configurationInternal = getConfigurationInternal(userId);
TimeZoneCapabilities capabilities =
@@ -248,7 +253,7 @@
TimeZoneConfiguration oldConfiguration = configurationInternal.asConfiguration();
final TimeZoneConfiguration newConfiguration =
- capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration);
+ capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfigurationUpdates);
if (newConfiguration == null) {
// The changes could not be made because the user's capabilities do not allow it.
return false;
@@ -256,7 +261,7 @@
// Store the configuration / notify as needed. This will cause the mEnvironment to invoke
// handleConfigChanged() asynchronously.
- storeConfiguration(userId, newConfiguration);
+ storeConfiguration(userId, requestedConfigurationUpdates, newConfiguration);
return true;
}
@@ -268,15 +273,20 @@
*/
@GuardedBy("this")
private void storeConfiguration(@UserIdInt int userId,
- @NonNull TimeZoneConfiguration configuration) {
- Objects.requireNonNull(configuration);
+ @NonNull TimeZoneConfiguration requestedConfigurationUpdates,
+ @NonNull TimeZoneConfiguration newConfiguration) {
+ Objects.requireNonNull(newConfiguration);
// Avoid writing the auto detection enabled setting for devices that do not support auto
// time zone detection: if we wrote it down then we'd set the value explicitly, which would
// prevent detecting "default" later. That might influence what happens on later releases
// that support new types of auto detection on the same hardware.
if (isAutoDetectionFeatureSupported()) {
- final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
+ if (requestedConfigurationUpdates.hasIsAutoDetectionEnabled()) {
+ // Record that the auto detection enabled setting has now been set explicitly.
+ Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE_EXPLICIT, 1);
+ }
+ final boolean autoDetectionEnabled = newConfiguration.isAutoDetectionEnabled();
setAutoDetectionEnabledIfRequired(autoDetectionEnabled);
// Only write the geo detection enabled setting when its values is used, e.g.:
@@ -288,10 +298,10 @@
// Not being able to detect if the user has actually expressed a preference could
// influence what happens on later releases that start to support geo detection on the
// user's same hardware.
- if (!getGeoDetectionSettingEnabledOverride().isPresent()
+ if (getGeoDetectionSettingEnabledOverride().isEmpty()
&& isGeoTimeZoneDetectionFeatureSupported()
&& isTelephonyTimeZoneDetectionFeatureSupported()) {
- final boolean geoDetectionEnabledSetting = configuration.isGeoDetectionEnabled();
+ final boolean geoDetectionEnabledSetting = newConfiguration.isGeoDetectionEnabled();
setGeoDetectionEnabledSettingIfRequired(userId, geoDetectionEnabledSetting);
}
}
@@ -335,7 +345,31 @@
}
private boolean getAutoDetectionEnabledSetting() {
- return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+ boolean autoDetectionEnabledSetting =
+ Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+
+ Optional<Boolean> optionalFlagValue = mServerFlags.getOptionalBoolean(
+ ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT);
+ if (optionalFlagValue.isPresent()) {
+ // This branch is rare: it is expected to happen only for internal testers.
+
+ if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE_EXPLICIT, 0) == 0) {
+ // The device hasn't explicitly had the auto detection enabled setting updated via a
+ // call to storeConfiguration(). This means the device is allowed to use a server
+ // flag to determine the default.
+ boolean flagValue = optionalFlagValue.get();
+
+ // Best effort to keep the setting in sync with the flag in case something is
+ // observing the (public API) Settings.Global.AUTO_TIME_ZONE directly. This change
+ // will cause listeners to fire asynchronously but any cascade should stop after one
+ // round.
+ if (flagValue != autoDetectionEnabledSetting) {
+ Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, flagValue ? 1 : 0);
+ }
+ autoDetectionEnabledSetting = flagValue;
+ }
+ }
+ return autoDetectionEnabledSetting;
}
private boolean getGeoDetectionEnabledSetting(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index ab68e83..d1ddb58 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -37,6 +37,7 @@
import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_RUN_IN_BACKGROUND_ENABLED;
import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT;
import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE;
+import static com.android.server.timedetector.ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT;
import static com.android.server.timedetector.ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED;
import android.app.time.LocationTimeZoneManager;
@@ -308,6 +309,10 @@
pw.printf(" %s\n", KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
pw.printf(" Used to override the device's 'geolocation time zone detection enabled'"
+ " setting [*].\n");
+ pw.printf(" %s\n", KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT);
+ pw.printf(" Used to set the automatic time zone detection enabled default, i.e. when the"
+ + " device's automatic time zone detection enabled setting hasn't been set"
+ + " explicitly. Intended for internal testers.");
pw.printf(" %s\n", KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED);
pw.printf(" Used to enable / disable support for telephony detection fallback. Also see"
+ " the %s command.\n", SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index a327a42..9069ac5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -100,6 +100,7 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
@@ -837,6 +838,13 @@
/** Whether the input to this activity will be dropped during the current playing animation. */
private boolean mIsInputDroppedForAnimation;
+ /**
+ * Whether the application has desk mode resources. Calculated and cached when
+ * {@link #hasDeskResources()} is called.
+ */
+ @Nullable
+ private Boolean mHasDeskResources;
+
boolean mHandleExitSplashScreen;
@TransferSplashScreenState
int mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
@@ -3978,6 +3986,7 @@
"Reported destroyed for activity that is not destroying: r=" + this);
}
+ mTaskSupervisor.killTaskProcessesOnDestroyedIfNeeded(task);
if (isInRootTaskLocked()) {
cleanUp(true /* cleanServices */, false /* setState */);
removeFromHistory(reason);
@@ -9059,8 +9068,13 @@
}
if (activityType != ACTIVITY_TYPE_UNDEFINED
&& activityType != getActivityType()) {
- Slog.w(TAG, "Can't change activity type once set: " + this
- + " activityType=" + activityTypeToString(getActivityType()));
+ final String errorMessage = "Can't change activity type once set: " + this
+ + " activityType=" + activityTypeToString(getActivityType()) + ", was "
+ + activityTypeToString(activityType);
+ if (Build.IS_DEBUGGABLE) {
+ throw new IllegalStateException(errorMessage);
+ }
+ Slog.w(TAG, errorMessage);
}
// Configuration's equality doesn't consider seq so if only seq number changes in resolved
@@ -9547,7 +9561,14 @@
configChanged |= CONFIG_UI_MODE;
}
- return (changes&(~configChanged)) != 0;
+ // TODO(b/274944389): remove workaround after long-term solution is implemented
+ // Don't restart due to desk mode change if the app does not have desk resources.
+ if (mWmService.mSkipActivityRelaunchWhenDocking && onlyDeskInUiModeChanged(changesConfig)
+ && !hasDeskResources()) {
+ configChanged |= CONFIG_UI_MODE;
+ }
+
+ return (changes & (~configChanged)) != 0;
}
/**
@@ -9560,6 +9581,50 @@
!= isInVrUiMode(lastReportedConfig));
}
+ /**
+ * Returns true if the uiMode configuration changed, and desk mode
+ * ({@link android.content.res.Configuration#UI_MODE_TYPE_DESK}) was the only change to uiMode.
+ */
+ private boolean onlyDeskInUiModeChanged(Configuration lastReportedConfig) {
+ final Configuration currentConfig = getConfiguration();
+
+ boolean deskModeChanged = isInDeskUiMode(currentConfig) != isInDeskUiMode(
+ lastReportedConfig);
+ // UI mode contains fields other than the UI mode type, so determine if any other fields
+ // changed.
+ boolean uiModeOtherFieldsChanged =
+ (currentConfig.uiMode & ~UI_MODE_TYPE_MASK) != (lastReportedConfig.uiMode
+ & ~UI_MODE_TYPE_MASK);
+
+ return deskModeChanged && !uiModeOtherFieldsChanged;
+ }
+
+ /**
+ * Determines whether or not the application has desk mode resources.
+ */
+ boolean hasDeskResources() {
+ if (mHasDeskResources != null) {
+ // We already determined this, return the cached value.
+ return mHasDeskResources;
+ }
+
+ mHasDeskResources = false;
+ try {
+ Resources packageResources = mAtmService.mContext.createPackageContextAsUser(
+ packageName, 0, UserHandle.of(mUserId)).getResources();
+ for (Configuration sizeConfiguration :
+ packageResources.getSizeAndUiModeConfigurations()) {
+ if (isInDeskUiMode(sizeConfiguration)) {
+ mHasDeskResources = true;
+ break;
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Exception thrown during checking for desk resources " + this, e);
+ }
+ return mHasDeskResources;
+ }
+
private int getConfigurationChanges(Configuration lastReportedConfig) {
// Determine what has changed. May be nothing, if this is a config that has come back from
// the app after going idle. In that case we just want to leave the official config object
@@ -9891,6 +9956,10 @@
return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
}
+ private static boolean isInDeskUiMode(Configuration config) {
+ return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_DESK;
+ }
+
String getProcessName() {
return info.applicationInfo.processName;
}
@@ -10428,6 +10497,11 @@
@Override
boolean isSyncFinished() {
+ if (task != null && mTransitionController.isTransientHide(task)) {
+ // The activity keeps visibleRequested but may be hidden later, so no need to wait for
+ // it to be drawn.
+ return true;
+ }
if (!super.isSyncFinished()) return false;
if (mDisplayContent != null && mDisplayContent.mUnknownAppVisibilityController
.isVisibilityUnknown(this)) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index eaf5583..be503fc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -190,12 +190,19 @@
/** How long we wait until giving up on the activity telling us it released the top state. */
private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500;
+ /**
+ * The timeout to kill task processes if its activity didn't complete destruction in time
+ * when there is a request to remove the task with killProcess=true.
+ */
+ private static final int KILL_TASK_PROCESSES_TIMEOUT_MS = 1000;
+
private static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG;
private static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_TASK_MSG + 1;
private static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_TASK_MSG + 2;
private static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 3;
private static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 4;
private static final int PROCESS_STOPPING_AND_FINISHING_MSG = FIRST_SUPERVISOR_TASK_MSG + 5;
+ private static final int KILL_TASK_PROCESSES_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 6;
private static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_TASK_MSG + 12;
private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 13;
private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_TASK_MSG + 14;
@@ -1642,10 +1649,32 @@
return;
}
task.mTransitionController.requestCloseTransitionIfNeeded(task);
+ // Consume the stopping activities immediately so activity manager won't skip killing
+ // the process because it is still foreground state, i.e. RESUMED -> PAUSING set from
+ // removeActivities -> finishIfPossible.
+ if (killProcess) {
+ ArrayList<ActivityRecord> activities = null;
+ for (int i = mStoppingActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = mStoppingActivities.get(i);
+ if (r.getTask() == task) {
+ if (activities == null) {
+ activities = new ArrayList<>();
+ }
+ activities.add(r);
+ mStoppingActivities.remove(i);
+ }
+ }
+ if (activities != null) {
+ // This can update to background state.
+ for (int i = activities.size() - 1; i >= 0; i--) {
+ activities.get(i).stopIfPossible();
+ }
+ }
+ }
task.mInRemoveTask = true;
try {
task.removeActivities(reason, false /* excludingTaskOverlay */);
- cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
+ cleanUpRemovedTask(task, killProcess, removeFromRecents);
mService.getLockTaskController().clearLockedTask(task);
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
if (task.isPersistable) {
@@ -1825,11 +1854,13 @@
}
}
- void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
+ /** This method should only be called for leaf task. */
+ private void cleanUpRemovedTask(Task task, boolean killProcess, boolean removeFromRecents) {
if (removeFromRecents) {
mRecentTasks.remove(task);
}
- ComponentName component = task.getBaseIntent().getComponent();
+ final Intent baseIntent = task.getBaseIntent();
+ final ComponentName component = baseIntent != null ? baseIntent.getComponent() : null;
if (component == null) {
Slog.w(TAG, "No component for base intent of task: " + task);
return;
@@ -1837,16 +1868,38 @@
// Find any running services associated with this app and stop if needed.
final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::cleanUpServices,
- mService.mAmInternal, task.mUserId, component, new Intent(task.getBaseIntent()));
+ mService.mAmInternal, task.mUserId, component, new Intent(baseIntent));
mService.mH.sendMessage(msg);
if (!killProcess) {
return;
}
+ // Give a chance for the client to handle Activity#onStop(). The timeout waits for
+ // onDestroy because the client defers to report completion of stopped, the callback from
+ // DestroyActivityItem may be called first.
+ final ActivityRecord top = task.getTopMostActivity();
+ if (top != null && top.finishing && !top.mAppStopped && top.lastVisibleTime > 0
+ && !task.mKillProcessesOnDestroyed) {
+ task.mKillProcessesOnDestroyed = true;
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(KILL_TASK_PROCESSES_TIMEOUT_MSG, task),
+ KILL_TASK_PROCESSES_TIMEOUT_MS);
+ return;
+ }
+ killTaskProcessesIfPossible(task);
+ }
- // Determine if the process(es) for this task should be killed.
- final String pkg = component.getPackageName();
- ArrayList<Object> procsToKill = new ArrayList<>();
+ void killTaskProcessesOnDestroyedIfNeeded(Task task) {
+ if (task == null || !task.mKillProcessesOnDestroyed) return;
+ mHandler.removeMessages(KILL_TASK_PROCESSES_TIMEOUT_MSG, task);
+ killTaskProcessesIfPossible(task);
+ }
+
+ /** Kills the processes in the task if it doesn't contain perceptible components. */
+ private void killTaskProcessesIfPossible(Task task) {
+ task.mKillProcessesOnDestroyed = false;
+ final String pkg = task.getBasePackageName();
+ ArrayList<Object> procsToKill = null;
ArrayMap<String, SparseArray<WindowProcessController>> pmap =
mService.mProcessNames.getMap();
for (int i = 0; i < pmap.size(); i++) {
@@ -1878,10 +1931,14 @@
return;
}
+ if (procsToKill == null) {
+ procsToKill = new ArrayList<>();
+ }
// Add process to kill list.
procsToKill.add(proc);
}
}
+ if (procsToKill == null) return;
// Kill the running processes. Post on handle since we don't want to hold the service lock
// while calling into AM.
@@ -2677,6 +2734,13 @@
processStoppingAndFinishingActivities(null /* launchedActivity */,
false /* processPausingActivities */, "transit");
} break;
+ case KILL_TASK_PROCESSES_TIMEOUT_MSG: {
+ final Task task = (Task) msg.obj;
+ if (task.mKillProcessesOnDestroyed) {
+ Slog.i(TAG, "Destroy timeout of remove-task, attempt to kill " + task);
+ killTaskProcessesIfPossible(task);
+ }
+ } break;
case LAUNCH_TASK_BEHIND_COMPLETE: {
final ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
if (r != null) {
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 2344739596..6773bcd 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
+import static com.android.internal.util.Preconditions.checkState;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -45,6 +46,7 @@
import android.util.DebugUtils;
import android.util.Slog;
+
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;
@@ -59,6 +61,9 @@
private static final String TAG =
TAG_WITH_CLASS_NAME ? "BackgroundActivityStartController" : TAG_ATM;
+ public static final String VERDICT_ALLOWED = "Activity start allowed";
+ public static final String VERDICT_WOULD_BE_ALLOWED_IF_SENDER_GRANTS_BAL =
+ "Activity start would be allowed if the sender granted BAL privileges";
private final ActivityTaskManagerService mService;
private final ActivityTaskSupervisor mSupervisor;
@@ -234,10 +239,6 @@
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
- final boolean isCallingUidForeground =
- callingUidHasAnyVisibleWindow
- || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
- || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
final boolean isCallingUidPersistentSystemProcess =
callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
@@ -266,11 +267,6 @@
(callingUid == realCallingUid)
? callingUidHasAnyVisibleWindow
: mService.hasActiveVisibleWindow(realCallingUid);
- final boolean isRealCallingUidForeground =
- (callingUid == realCallingUid)
- ? isCallingUidForeground
- : realCallingUidHasAnyVisibleWindow
- || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
final int realCallingAppId = UserHandle.getAppId(realCallingUid);
final boolean isRealCallingUidPersistentSystemProcess =
(callingUid == realCallingUid)
@@ -297,75 +293,63 @@
final BackgroundStartPrivileges balAllowedByPiSender =
PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller(
checkedOptions, realCallingUid);
- if (balAllowedByPiSender.allowsBackgroundActivityStarts()
- && realCallingUid != callingUid) {
- final boolean useCallerPermission =
- PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
- if (useCallerPermission
- && ActivityManager.checkComponentPermission(
- android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
- realCallingUid,
- -1,
- true)
- == PackageManager.PERMISSION_GRANTED) {
- return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
- /*background*/ false, callingUid, realCallingUid, intent,
- "realCallingUid has BAL permission. realCallingUid: " + realCallingUid);
- }
- // don't abort if the realCallingUid has a visible window
- // TODO(b/171459802): We should check appSwitchAllowed also
- if (realCallingUidHasAnyVisibleWindow) {
- return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
- /*background*/ false, callingUid, realCallingUid, intent,
- "realCallingUid has visible (non-toast) window. realCallingUid: "
- + realCallingUid);
- }
- // if the realCallingUid is a persistent system process, abort if the IntentSender
- // wasn't allowed to start an activity
- if (isRealCallingUidPersistentSystemProcess
- && backgroundStartPrivileges.allowsBackgroundActivityStarts()) {
- return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
- /*background*/ false, callingUid, realCallingUid, intent,
- "realCallingUid is persistent system process AND intent "
- + "sender allowed (allowBackgroundActivityStart = true). "
- + "realCallingUid: " + realCallingUid);
- }
- // don't abort if the realCallingUid is an associated companion app
- if (mService.isAssociatedCompanionApp(
- UserHandle.getUserId(realCallingUid), realCallingUid)) {
- return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
- /*background*/ false, callingUid, realCallingUid, intent,
- "realCallingUid is a companion app. "
- + "realCallingUid: " + realCallingUid);
- }
+ final boolean logVerdictChangeByPiDefaultChange = checkedOptions == null
+ || checkedOptions.getPendingIntentBackgroundActivityStartMode()
+ == ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
+ final boolean considerPiRules = logVerdictChangeByPiDefaultChange
+ || balAllowedByPiSender.allowsBackgroundActivityStarts();
+ final String verdictLogForPiSender =
+ balAllowedByPiSender.allowsBackgroundActivityStarts() ? VERDICT_ALLOWED
+ : VERDICT_WOULD_BE_ALLOWED_IF_SENDER_GRANTS_BAL;
+
+ @BalCode int resultIfPiSenderAllowsBal = BAL_BLOCK;
+ if (realCallingUid != callingUid && considerPiRules) {
+ resultIfPiSenderAllowsBal = checkPiBackgroundActivityStart(callingUid, realCallingUid,
+ backgroundStartPrivileges, intent, checkedOptions,
+ realCallingUidHasAnyVisibleWindow, isRealCallingUidPersistentSystemProcess,
+ verdictLogForPiSender);
+ }
+ if (resultIfPiSenderAllowsBal != BAL_BLOCK
+ && balAllowedByPiSender.allowsBackgroundActivityStarts()
+ && !logVerdictChangeByPiDefaultChange) {
+ // The result is to allow (because the sender allows BAL) and we are not interested in
+ // logging differences, so just return.
+ return resultIfPiSenderAllowsBal;
}
if (useCallingUidState) {
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
if (ActivityTaskManagerService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND,
callingPid, callingUid) == PERMISSION_GRANTED) {
return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
- /*background*/ true, callingUid, realCallingUid, intent,
- "START_ACTIVITIES_FROM_BACKGROUND permission granted");
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
+ /*background*/ true, callingUid, realCallingUid, intent,
+ "START_ACTIVITIES_FROM_BACKGROUND permission granted");
}
// don't abort if the caller has the same uid as the recents component
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
- return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ true, callingUid, realCallingUid,
- intent, "Recents Component");
+ return logStartAllowedAndReturnCode(
+ BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "Recents Component");
}
// don't abort if the callingUid is the device owner
if (mService.isDeviceOwner(callingUid)) {
- return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ true, callingUid, realCallingUid,
- intent, "Device Owner");
+ return logStartAllowedAndReturnCode(
+ BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "Device Owner");
}
// don't abort if the callingUid has companion device
final int callingUserId = UserHandle.getUserId(callingUid);
if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
- return logStartAllowedAndReturnCode(BAL_ALLOW_ALLOWLISTED_COMPONENT,
- /*background*/ true, callingUid, realCallingUid,
- intent, "Companion App");
+ return logStartAllowedAndReturnCode(
+ BAL_ALLOW_ALLOWLISTED_COMPONENT,
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "Companion App");
}
// don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
@@ -374,18 +358,19 @@
"Background activity start for "
+ callingPackage
+ " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
- return logStartAllowedAndReturnCode(BAL_ALLOW_SAW_PERMISSION,
- /*background*/ true, callingUid, realCallingUid,
- intent, "SYSTEM_ALERT_WINDOW permission is granted");
+ return logStartAllowedAndReturnCode(
+ BAL_ALLOW_SAW_PERMISSION,
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
+ /*background*/ true, callingUid, realCallingUid,
+ intent, "SYSTEM_ALERT_WINDOW permission is granted");
}
// don't abort if the callingUid and callingPackage have the
// OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop
if (isSystemExemptFlagEnabled() && mService.getAppOpsManager().checkOpNoThrow(
- AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
- callingUid,
- callingPackage)
- == AppOpsManager.MODE_ALLOWED) {
+ AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
+ callingUid, callingPackage) == AppOpsManager.MODE_ALLOWED) {
return logStartAllowedAndReturnCode(BAL_ALLOW_PERMISSION,
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
/*background*/ true, callingUid, realCallingUid, intent,
"OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop is granted");
}
@@ -395,78 +380,119 @@
// up and alive. If that's the case, we retrieve the WindowProcessController for the send()
// caller if caller allows, so that we can make the decision based on its state.
int callerAppUid = callingUid;
- if (callerApp == null && balAllowedByPiSender.allowsBackgroundActivityStarts()) {
+ boolean callerAppBasedOnPiSender = callerApp == null && considerPiRules
+ && resultIfPiSenderAllowsBal == BAL_BLOCK;
+ if (callerAppBasedOnPiSender) {
callerApp = mService.getProcessController(realCallingPid, realCallingUid);
callerAppUid = realCallingUid;
}
// don't abort if the callerApp or other processes of that uid are allowed in any way
if (callerApp != null && useCallingUidState) {
// first check the original calling process
- @BalCode int balAllowedForCaller = callerApp
+ final @BalCode int balAllowedForCaller = callerApp
.areBackgroundActivityStartsAllowed(appSwitchState);
if (balAllowedForCaller != BAL_BLOCK) {
- return logStartAllowedAndReturnCode(balAllowedForCaller,
+ if (callerAppBasedOnPiSender) {
+ resultIfPiSenderAllowsBal = logStartAllowedAndReturnCode(balAllowedForCaller,
/*background*/ true, callingUid, realCallingUid, intent,
"callerApp process (pid = " + callerApp.getPid()
- + ", uid = " + callerAppUid + ") is allowed");
- }
- // only if that one wasn't allowed, check the other ones
- final ArraySet<WindowProcessController> uidProcesses =
+ + ", uid = " + callerAppUid + ") is allowed", verdictLogForPiSender);
+ } else {
+ return logStartAllowedAndReturnCode(balAllowedForCaller,
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
+ /*background*/ true, callingUid, realCallingUid, intent,
+ "callerApp process (pid = " + callerApp.getPid()
+ + ", uid = " + callerAppUid + ") is allowed");
+ }
+ } else {
+ // only if that one wasn't allowed, check the other ones
+ final ArraySet<WindowProcessController> uidProcesses =
mService.mProcessMap.getProcesses(callerAppUid);
- if (uidProcesses != null) {
- for (int i = uidProcesses.size() - 1; i >= 0; i--) {
- final WindowProcessController proc = uidProcesses.valueAt(i);
- int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(appSwitchState);
- if (proc != callerApp
- && balAllowedForUid != BAL_BLOCK) {
- return logStartAllowedAndReturnCode(balAllowedForUid,
- /*background*/ true, callingUid, realCallingUid, intent,
- "process" + proc.getPid()
- + " from uid " + callerAppUid + " is allowed");
+ if (uidProcesses != null) {
+ for (int i = uidProcesses.size() - 1; i >= 0; i--) {
+ final WindowProcessController proc = uidProcesses.valueAt(i);
+ int balAllowedForUid = proc.areBackgroundActivityStartsAllowed(
+ appSwitchState);
+ if (proc != callerApp && balAllowedForUid != BAL_BLOCK) {
+ if (callerAppBasedOnPiSender) {
+ resultIfPiSenderAllowsBal = logStartAllowedAndReturnCode(
+ balAllowedForUid,
+ /*background*/ true, callingUid, realCallingUid, intent,
+ "process" + proc.getPid() + " from uid " + callerAppUid
+ + " is allowed", verdictLogForPiSender);
+ break;
+ } else {
+ return logStartAllowedAndReturnCode(balAllowedForUid,
+ resultIfPiSenderAllowsBal, balAllowedByPiSender,
+ /*background*/ true, callingUid, realCallingUid, intent,
+ "process" + proc.getPid() + " from uid " + callerAppUid
+ + " is allowed");
+ }
+ }
}
}
}
+ if (callerAppBasedOnPiSender) {
+ // If caller app was based on PI sender, this result is part of
+ // resultIfPiSenderAllowsBal
+ if (resultIfPiSenderAllowsBal != BAL_BLOCK
+ && balAllowedByPiSender.allowsBackgroundActivityStarts()
+ && !logVerdictChangeByPiDefaultChange) {
+ // The result is to allow (because the sender allows BAL) and we are not
+ // interested in logging differences, so just return.
+ return resultIfPiSenderAllowsBal;
+ }
+ } else {
+ // If caller app was NOT based on PI sender and we found a allow reason we should
+ // have returned already
+ checkState(balAllowedForCaller == BAL_BLOCK,
+ "balAllowedForCaller = " + balAllowedForCaller + " (should have returned)");
+ }
+ }
+ // If we are here, it means all exemptions not based on PI sender failed, so we'll block
+ // unless resultIfPiSenderAllowsBal is an allow and the PI sender allows BAL
+
+ String stateDumpLog = " [callingPackage: " + callingPackage
+ + "; callingUid: " + callingUid
+ + "; appSwitchState: " + appSwitchState
+ + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
+ + "; callingUidProcState: " + DebugUtils.valueToString(
+ ActivityManager.class, "PROCESS_STATE_", callingUidProcState)
+ + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
+ + "; balAllowedByPiSender: " + balAllowedByPiSender
+ + "; realCallingUid: " + realCallingUid
+ + "; realCallingUidHasAnyVisibleWindow: " + realCallingUidHasAnyVisibleWindow
+ + "; realCallingUidProcState: " + DebugUtils.valueToString(
+ ActivityManager.class, "PROCESS_STATE_", realCallingUidProcState)
+ + "; isRealCallingUidPersistentSystemProcess: "
+ + isRealCallingUidPersistentSystemProcess
+ + "; originatingPendingIntent: " + originatingPendingIntent
+ + "; backgroundStartPrivileges: " + backgroundStartPrivileges
+ + "; intent: " + intent
+ + "; callerApp: " + callerApp
+ + "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask())
+ + "]";
+ if (resultIfPiSenderAllowsBal != BAL_BLOCK) {
+ // We should have returned before if !logVerdictChangeByPiDefaultChange
+ checkState(logVerdictChangeByPiDefaultChange,
+ "resultIfPiSenderAllowsBal = " + balCodeToString(resultIfPiSenderAllowsBal)
+ + " at the end but logVerdictChangeByPiDefaultChange = false");
+ if (balAllowedByPiSender.allowsBackgroundActivityStarts()) {
+ // The verdict changed from block to allow, PI sender default change is off and
+ // we'd block if it were on
+ Slog.wtf(TAG, "With BAL hardening this activity start would be blocked!"
+ + stateDumpLog);
+ return resultIfPiSenderAllowsBal;
+ } else {
+ // The verdict changed from allow (resultIfPiSenderAllowsBal) to block, PI sender
+ // default change is on (otherwise we would have fallen into if above) and we'd
+ // allow if it were off
+ Slog.wtf(TAG, "Without BAL hardening this activity start would NOT be allowed!"
+ + stateDumpLog);
+ }
}
// anything that has fallen through would currently be aborted
- Slog.w(
- TAG,
- "Background activity launch blocked [callingPackage: "
- + callingPackage
- + "; callingUid: "
- + callingUid
- + "; appSwitchState: "
- + appSwitchState
- + "; isCallingUidForeground: "
- + isCallingUidForeground
- + "; callingUidHasAnyVisibleWindow: "
- + callingUidHasAnyVisibleWindow
- + "; callingUidProcState: "
- + DebugUtils.valueToString(
- ActivityManager.class, "PROCESS_STATE_", callingUidProcState)
- + "; isCallingUidPersistentSystemProcess: "
- + isCallingUidPersistentSystemProcess
- + "; realCallingUid: "
- + realCallingUid
- + "; isRealCallingUidForeground: "
- + isRealCallingUidForeground
- + "; realCallingUidHasAnyVisibleWindow: "
- + realCallingUidHasAnyVisibleWindow
- + "; realCallingUidProcState: "
- + DebugUtils.valueToString(
- ActivityManager.class, "PROCESS_STATE_", realCallingUidProcState)
- + "; isRealCallingUidPersistentSystemProcess: "
- + isRealCallingUidPersistentSystemProcess
- + "; originatingPendingIntent: "
- + originatingPendingIntent
- + "; backgroundStartPrivileges: "
- + backgroundStartPrivileges
- + "; intent: "
- + intent
- + "; callerApp: "
- + callerApp
- + "; inVisibleTask: "
- + (callerApp != null && callerApp.hasActivityInVisibleTask())
- + "]");
+ Slog.w(TAG, "Background activity launch blocked" + stateDumpLog);
// log aborted activity start to TRON
if (mService.isActivityStartsLoggingEnabled()) {
mSupervisor
@@ -486,6 +512,51 @@
return BAL_BLOCK;
}
+ private @BalCode int checkPiBackgroundActivityStart(int callingUid, int realCallingUid,
+ BackgroundStartPrivileges backgroundStartPrivileges, Intent intent,
+ ActivityOptions checkedOptions, boolean realCallingUidHasAnyVisibleWindow,
+ boolean isRealCallingUidPersistentSystemProcess, String verdictLog) {
+ final boolean useCallerPermission =
+ PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
+ if (useCallerPermission
+ && ActivityManager.checkComponentPermission(
+ android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+ realCallingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
+ "realCallingUid has BAL permission. realCallingUid: " + realCallingUid,
+ verdictLog);
+ }
+
+ // don't abort if the realCallingUid has a visible window
+ // TODO(b/171459802): We should check appSwitchAllowed also
+ if (realCallingUidHasAnyVisibleWindow) {
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
+ "realCallingUid has visible (non-toast) window. realCallingUid: "
+ + realCallingUid, verdictLog);
+ }
+ // if the realCallingUid is a persistent system process, abort if the IntentSender
+ // wasn't allowed to start an activity
+ if (isRealCallingUidPersistentSystemProcess
+ && backgroundStartPrivileges.allowsBackgroundActivityStarts()) {
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
+ "realCallingUid is persistent system process AND intent "
+ + "sender allowed (allowBackgroundActivityStart = true). "
+ + "realCallingUid: " + realCallingUid, verdictLog);
+ }
+ // don't abort if the realCallingUid is an associated companion app
+ if (mService.isAssociatedCompanionApp(
+ UserHandle.getUserId(realCallingUid), realCallingUid)) {
+ return logStartAllowedAndReturnCode(BAL_ALLOW_PENDING_INTENT,
+ /*background*/ false, callingUid, realCallingUid, intent,
+ "realCallingUid is a companion app. "
+ + "realCallingUid: " + realCallingUid, verdictLog);
+ }
+ return BAL_BLOCK;
+ }
+
static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
int callingUid, int realCallingUid, Intent intent, int pid, String msg) {
return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent,
@@ -494,16 +565,43 @@
static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
int callingUid, int realCallingUid, Intent intent, String msg) {
+ return logStartAllowedAndReturnCode(code, background, callingUid, realCallingUid, intent,
+ msg, VERDICT_ALLOWED);
+ }
+
+ /**
+ * Logs the start and returns one of the provided codes depending on if the PI sender allows
+ * using its BAL privileges.
+ */
+ static @BalCode int logStartAllowedAndReturnCode(@BalCode int result,
+ @BalCode int resultIfPiSenderAllowsBal, BackgroundStartPrivileges balAllowedByPiSender,
+ boolean background, int callingUid, int realCallingUid, Intent intent, String msg) {
+ if (resultIfPiSenderAllowsBal != BAL_BLOCK
+ && balAllowedByPiSender.allowsBackgroundActivityStarts()) {
+ // resultIfPiSenderAllowsBal was already logged, so just return
+ return resultIfPiSenderAllowsBal;
+ }
+ return logStartAllowedAndReturnCode(result, background, callingUid, realCallingUid,
+ intent, msg, VERDICT_ALLOWED);
+ }
+
+
+ static @BalCode int logStartAllowedAndReturnCode(@BalCode int code, boolean background,
+ int callingUid, int realCallingUid, Intent intent, String msg, String verdict) {
statsLogBalAllowed(code, callingUid, realCallingUid, intent);
if (DEBUG_ACTIVITY_STARTS) {
StringBuilder builder = new StringBuilder();
if (background) {
builder.append("Background ");
}
- builder.append("Activity start allowed: " + msg + ". callingUid: " + callingUid + ". ");
+ builder.append(verdict + ": " + msg + ". callingUid: " + callingUid + ". ");
builder.append("BAL Code: ");
builder.append(balCodeToString(code));
- Slog.d(TAG, builder.toString());
+ if (verdict.equals(VERDICT_ALLOWED)) {
+ Slog.i(TAG, builder.toString());
+ } else {
+ Slog.d(TAG, builder.toString());
+ }
}
return code;
}
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index d5828ef..c6978fd 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
@@ -62,37 +61,60 @@
import java.util.Map;
public final class CompatModePackages {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_ATM;
- private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
-
- private final ActivityTaskManagerService mService;
- private GameManagerInternal mGameManager;
- private final AtomicFile mFile;
-
- // Compatibility state: no longer ask user to select the mode.
- private static final int COMPAT_FLAG_DONT_ASK = 1<<0;
- // Compatibility state: compatibility mode is enabled.
- private static final int COMPAT_FLAG_ENABLED = 1<<1;
+ /**
+ * {@link CompatModePackages#DOWNSCALED_INVERSE} is the gatekeeper of all per-app buffer inverse
+ * downscale changes. Enabling this change will allow the following scaling factors:
+ * {@link CompatModePackages#DOWNSCALE_90}
+ * {@link CompatModePackages#DOWNSCALE_85}
+ * {@link CompatModePackages#DOWNSCALE_80}
+ * {@link CompatModePackages#DOWNSCALE_75}
+ * {@link CompatModePackages#DOWNSCALE_70}
+ * {@link CompatModePackages#DOWNSCALE_65}
+ * {@link CompatModePackages#DOWNSCALE_60}
+ * {@link CompatModePackages#DOWNSCALE_55}
+ * {@link CompatModePackages#DOWNSCALE_50}
+ * {@link CompatModePackages#DOWNSCALE_45}
+ * {@link CompatModePackages#DOWNSCALE_40}
+ * {@link CompatModePackages#DOWNSCALE_35}
+ * {@link CompatModePackages#DOWNSCALE_30}
+ *
+ * If {@link CompatModePackages#DOWNSCALED_INVERSE} is enabled for an app package, then the app
+ * will be forcibly resized to the lowest enabled scaling factor e.g. 1/0.8 if both 1/0.8 and
+ * 1/0.7 (* 100%) were enabled.
+ *
+ * When both {@link CompatModePackages#DOWNSCALED_INVERSE}
+ * and {@link CompatModePackages#DOWNSCALED} are enabled, then
+ * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALED_INVERSE = 273564678L; // This is a Bug ID.
/**
- * CompatModePackages#DOWNSCALED is the gatekeeper of all per-app buffer downscaling
- * changes. Disabling this change will prevent the following scaling factors from working:
- * CompatModePackages#DOWNSCALE_90
- * CompatModePackages#DOWNSCALE_85
- * CompatModePackages#DOWNSCALE_80
- * CompatModePackages#DOWNSCALE_75
- * CompatModePackages#DOWNSCALE_70
- * CompatModePackages#DOWNSCALE_65
- * CompatModePackages#DOWNSCALE_60
- * CompatModePackages#DOWNSCALE_55
- * CompatModePackages#DOWNSCALE_50
- * CompatModePackages#DOWNSCALE_45
- * CompatModePackages#DOWNSCALE_40
- * CompatModePackages#DOWNSCALE_35
- * CompatModePackages#DOWNSCALE_30
+ * {@link CompatModePackages#DOWNSCALED} is the gatekeeper of all per-app buffer downscaling
+ * changes. Enabling this change will allow the following scaling factors:
+ * {@link CompatModePackages#DOWNSCALE_90}
+ * {@link CompatModePackages#DOWNSCALE_85}
+ * {@link CompatModePackages#DOWNSCALE_80}
+ * {@link CompatModePackages#DOWNSCALE_75}
+ * {@link CompatModePackages#DOWNSCALE_70}
+ * {@link CompatModePackages#DOWNSCALE_65}
+ * {@link CompatModePackages#DOWNSCALE_60}
+ * {@link CompatModePackages#DOWNSCALE_55}
+ * {@link CompatModePackages#DOWNSCALE_50}
+ * {@link CompatModePackages#DOWNSCALE_45}
+ * {@link CompatModePackages#DOWNSCALE_40}
+ * {@link CompatModePackages#DOWNSCALE_35}
+ * {@link CompatModePackages#DOWNSCALE_30}
*
- * If CompatModePackages#DOWNSCALED is enabled for an app package, then the app will be forcibly
- * resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were enabled.
+ * If {@link CompatModePackages#DOWNSCALED} is enabled for an app package, then the app will be
+ * forcibly resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were
+ * enabled.
+ *
+ * When both {@link CompatModePackages#DOWNSCALED_INVERSE}
+ * and {@link CompatModePackages#DOWNSCALED} are enabled, then
+ * {@link CompatModePackages#DOWNSCALED_INVERSE} takes precedence.
*/
@ChangeId
@Disabled
@@ -100,9 +122,12 @@
public static final long DOWNSCALED = 168419799L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_90 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_90} for a package will force the app to assume it's
* running on a display with 90% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 111.11% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -110,9 +135,12 @@
public static final long DOWNSCALE_90 = 182811243L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_85 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_85} for a package will force the app to assume it's
* running on a display with 85% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 117.65% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -120,9 +148,12 @@
public static final long DOWNSCALE_85 = 189969734L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_80 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_80} for a package will force the app to assume it's
* running on a display with 80% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 125% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -130,9 +161,12 @@
public static final long DOWNSCALE_80 = 176926753L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_75 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_75} for a package will force the app to assume it's
* running on a display with 75% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 133.33% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -140,9 +174,12 @@
public static final long DOWNSCALE_75 = 189969779L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_70 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_70} for a package will force the app to assume it's
* running on a display with 70% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 142.86% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -150,9 +187,12 @@
public static final long DOWNSCALE_70 = 176926829L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_65 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_65} for a package will force the app to assume it's
* running on a display with 65% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 153.85% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -160,9 +200,12 @@
public static final long DOWNSCALE_65 = 189969744L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_60 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_60} for a package will force the app to assume it's
* running on a display with 60% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 166.67% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -170,9 +213,12 @@
public static final long DOWNSCALE_60 = 176926771L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_55 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_55} for a package will force the app to assume it's
* running on a display with 55% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 181.82% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -180,9 +226,12 @@
public static final long DOWNSCALE_55 = 189970036L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_50 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_50} for a package will force the app to assume it's
* running on a display with 50% vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 200% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -190,9 +239,12 @@
public static final long DOWNSCALE_50 = 176926741L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_45 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_45} for a package will force the app to assume it's
* running on a display with 45% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 222.22% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -200,9 +252,12 @@
public static final long DOWNSCALE_45 = 189969782L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_40 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_40} for a package will force the app to assume it's
* running on a display with 40% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 250% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -210,9 +265,12 @@
public static final long DOWNSCALE_40 = 189970038L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_35 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_35} for a package will force the app to assume it's
* running on a display with 35% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 285.71% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -220,9 +278,12 @@
public static final long DOWNSCALE_35 = 189969749L;
/**
- * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
- * CompatModePackages#DOWNSCALE_30 for a package will force the app to assume it's
+ * With {@link CompatModePackages#DOWNSCALED} enabled, subsequently enabling change-id
+ * {@link CompatModePackages#DOWNSCALE_30} for a package will force the app to assume it's
* running on a display with 30% the vertical and horizontal resolution of the real display.
+ *
+ * With {@link CompatModePackages#DOWNSCALED_INVERSE} enabled will force the app to assume it's
+ * running on a display with 333.33% the vertical and horizontal resolution of the real display
*/
@ChangeId
@Disabled
@@ -240,11 +301,15 @@
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
private static final long DO_NOT_DOWNSCALE_TO_1080P_ON_TV = 157629738L; // This is a Bug ID.
- private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
-
private static final int MSG_WRITE = 300;
- private final CompatHandler mHandler;
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "CompatModePackages" : TAG_ATM;
+
+ // Compatibility state: no longer ask user to select the mode.
+ private static final int COMPAT_FLAG_DONT_ASK = 1 << 0;
+
+ // Compatibility state: compatibility mode is enabled.
+ private static final int COMPAT_FLAG_ENABLED = 1 << 1;
private final class CompatHandler extends Handler {
public CompatHandler(Looper looper) {
@@ -261,6 +326,12 @@
}
}
+ private final ActivityTaskManagerService mService;
+ private GameManagerInternal mGameManager;
+ private final AtomicFile mFile;
+ private final HashMap<String, Integer> mPackages = new HashMap<>();
+ private final CompatHandler mHandler;
+
public CompatModePackages(ActivityTaskManagerService service, File systemDir, Handler handler) {
mService = service;
mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"), "compat-mode");
@@ -390,45 +461,16 @@
}
}
- if (CompatChanges.isChangeEnabled(DOWNSCALED, packageName, userHandle)) {
- if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) {
- return 1f / 0.9f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_85, packageName, userHandle)) {
- return 1f / 0.85f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_80, packageName, userHandle)) {
- return 1f / 0.8f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) {
- return 1f / 0.75f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_70, packageName, userHandle)) {
- return 1f / 0.7f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_65, packageName, userHandle)) {
- return 1f / 0.65f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_60, packageName, userHandle)) {
- return 1f / 0.6f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_55, packageName, userHandle)) {
- return 1f / 0.55f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) {
- return 1f / 0.5f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_45, packageName, userHandle)) {
- return 1f / 0.45f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_40, packageName, userHandle)) {
- return 1f / 0.4f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_35, packageName, userHandle)) {
- return 1f / 0.35f;
- }
- if (CompatChanges.isChangeEnabled(DOWNSCALE_30, packageName, userHandle)) {
- return 1f / 0.3f;
+ final boolean isDownscaledEnabled = CompatChanges.isChangeEnabled(
+ DOWNSCALED, packageName, userHandle);
+ final boolean isDownscaledInverseEnabled = CompatChanges.isChangeEnabled(
+ DOWNSCALED_INVERSE, packageName, userHandle);
+ if (isDownscaledEnabled || isDownscaledInverseEnabled) {
+ final float scalingFactor = getScalingFactor(packageName, userHandle);
+ if (scalingFactor != 1f) {
+ // For Upscaling the returned factor must be scalingFactor
+ // For Downscaling the returned factor must be 1f / scalingFactor
+ return isDownscaledInverseEnabled ? scalingFactor : 1f / scalingFactor;
}
}
@@ -445,6 +487,49 @@
return 1f;
}
+ private static float getScalingFactor(String packageName, UserHandle userHandle) {
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) {
+ return 0.9f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_85, packageName, userHandle)) {
+ return 0.85f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_80, packageName, userHandle)) {
+ return 0.8f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) {
+ return 0.75f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_70, packageName, userHandle)) {
+ return 0.7f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_65, packageName, userHandle)) {
+ return 0.65f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_60, packageName, userHandle)) {
+ return 0.6f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_55, packageName, userHandle)) {
+ return 0.55f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) {
+ return 0.5f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_45, packageName, userHandle)) {
+ return 0.45f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_40, packageName, userHandle)) {
+ return 0.4f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_35, packageName, userHandle)) {
+ return 0.35f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_30, packageName, userHandle)) {
+ return 0.3f;
+ }
+ return 1f;
+ }
+
public int computeCompatModeLocked(ApplicationInfo ai) {
final CompatibilityInfo info = compatibilityInfoForPackageLocked(ai);
if (info.alwaysSupportsScreen()) {
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 41eb2c9..fb72d6c 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -378,10 +378,7 @@
// Checking whether an activity in fullscreen rather than the task as this camera
// compat treatment doesn't cover activity embedding.
if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- if (topActivity.mLetterboxUiController
- .isOverrideOrientationOnlyForCameraEnabled()) {
- topActivity.recomputeConfiguration();
- }
+ topActivity.mLetterboxUiController.recomputeConfigurationForCameraCompatIfNeeded();
mDisplayContent.updateOrientation();
return;
}
@@ -447,9 +444,7 @@
|| topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
return;
}
- if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
- topActivity.recomputeConfiguration();
- }
+ topActivity.mLetterboxUiController.recomputeConfigurationForCameraCompatIfNeeded();
mDisplayContent.updateOrientation();
}
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index ec04894..611cbc7 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -212,6 +212,10 @@
// otherwise the apps get blacked out when they are resumed and do not have focus yet.
private boolean mIsCompatFakeFocusEnabled;
+ // Whether should use split screen aspect ratio for the activity when camera compat treatment
+ // is enabled and activity is connected to the camera in fullscreen.
+ private final boolean mIsCameraCompatSplitScreenAspectRatioEnabled;
+
// Whether camera compatibility treatment is enabled.
// See DisplayRotationCompatPolicy for context.
private final boolean mIsCameraCompatTreatmentEnabled;
@@ -300,6 +304,8 @@
R.bool.config_letterboxIsEnabledForTranslucentActivities);
mIsCameraCompatTreatmentEnabled = mContext.getResources().getBoolean(
R.bool.config_isWindowManagerCameraCompatTreatmentEnabled);
+ mIsCameraCompatSplitScreenAspectRatioEnabled = mContext.getResources().getBoolean(
+ R.bool.config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled);
mIsCompatFakeFocusEnabled = mContext.getResources().getBoolean(
R.bool.config_isCompatFakeFocusEnabled);
mIsPolicyForIgnoringRequestedOrientationEnabled = mContext.getResources().getBoolean(
@@ -1122,6 +1128,14 @@
return mIsPolicyForIgnoringRequestedOrientationEnabled;
}
+ /**
+ * Whether should use split screen aspect ratio for the activity when camera compat treatment
+ * is enabled and activity is connected to the camera in fullscreen.
+ */
+ boolean isCameraCompatSplitScreenAspectRatioEnabled() {
+ return mIsCameraCompatSplitScreenAspectRatioEnabled;
+ }
+
/** Whether camera compatibility treatment is enabled. */
boolean isCameraCompatTreatmentEnabled(boolean checkDeviceConfig) {
return mIsCameraCompatTreatmentEnabled && (!checkDeviceConfig
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index d8a6d49..06603b7 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -390,13 +390,7 @@
+ mActivityRecord);
return true;
}
- DisplayContent displayContent = mActivityRecord.mDisplayContent;
- if (displayContent == null) {
- return false;
- }
- if (displayContent.mDisplayRotationCompatPolicy != null
- && displayContent.mDisplayRotationCompatPolicy
- .isTreatmentEnabledForActivity(mActivityRecord)) {
+ if (isCameraCompatTreatmentActive()) {
Slog.w(TAG, "Ignoring orientation update to "
+ screenOrientationToString(requestedOrientation)
+ " due to camera compat treatment for " + mActivityRecord);
@@ -634,6 +628,16 @@
mBooleanPropertyCameraCompatAllowForceRotation);
}
+ private boolean isCameraCompatTreatmentActive() {
+ DisplayContent displayContent = mActivityRecord.mDisplayContent;
+ if (displayContent == null) {
+ return false;
+ }
+ return displayContent.mDisplayRotationCompatPolicy != null
+ && displayContent.mDisplayRotationCompatPolicy
+ .isTreatmentEnabledForActivity(mActivityRecord);
+ }
+
private boolean isCompatChangeEnabled(long overrideChangeId) {
return mActivityRecord.info.isChangeEnabled(overrideChangeId);
}
@@ -896,13 +900,35 @@
}
float getFixedOrientationLetterboxAspectRatio(@NonNull Configuration parentConfiguration) {
- // Don't resize to split screen size when half folded if letterbox position is centered
+ return shouldUseSplitScreenAspectRatio(parentConfiguration)
+ ? getSplitScreenAspectRatio()
+ : mActivityRecord.shouldCreateCompatDisplayInsets()
+ ? getDefaultMinAspectRatioForUnresizableApps()
+ : getDefaultMinAspectRatio();
+ }
+
+ void recomputeConfigurationForCameraCompatIfNeeded() {
+ if (isOverrideOrientationOnlyForCameraEnabled()
+ || isCameraCompatSplitScreenAspectRatioAllowed()) {
+ mActivityRecord.recomputeConfiguration();
+ }
+ }
+
+ /**
+ * Whether we use split screen aspect ratio for the activity when camera compat treatment
+ * is active because the corresponding config is enabled and activity supports resizing.
+ */
+ private boolean isCameraCompatSplitScreenAspectRatioAllowed() {
+ return mLetterboxConfiguration.isCameraCompatSplitScreenAspectRatioEnabled()
+ && !mActivityRecord.shouldCreateCompatDisplayInsets();
+ }
+
+ private boolean shouldUseSplitScreenAspectRatio(@NonNull Configuration parentConfiguration) {
return isDisplayFullScreenAndSeparatingHinge()
- && getHorizontalPositionMultiplier(parentConfiguration) != 0.5f
- ? getSplitScreenAspectRatio()
- : mActivityRecord.shouldCreateCompatDisplayInsets()
- ? getDefaultMinAspectRatioForUnresizableApps()
- : getDefaultMinAspectRatio();
+ // Don't resize to split screen size when half folded and centered
+ && getHorizontalPositionMultiplier(parentConfiguration) != 0.5f
+ || isCameraCompatSplitScreenAspectRatioAllowed()
+ && isCameraCompatTreatmentActive();
}
private float getDefaultMinAspectRatioForUnresizableApps() {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index dcb7fe3..0c98fb5 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -1014,9 +1014,7 @@
*/
boolean isBaseOfLockedTask(String packageName) {
for (int i = 0; i < mLockTaskModeTasks.size(); i++) {
- final Intent bi = mLockTaskModeTasks.get(i).getBaseIntent();
- if (bi != null && packageName.equals(bi.getComponent()
- .getPackageName())) {
+ if (packageName.equals(mLockTaskModeTasks.get(i).getBasePackageName())) {
return true;
}
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index cb94146..dda0d6c 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -682,10 +682,8 @@
void removeTasksByPackageName(String packageName, int userId) {
for (int i = mTasks.size() - 1; i >= 0; --i) {
final Task task = mTasks.get(i);
- final String taskPackageName =
- task.getBaseIntent().getComponent().getPackageName();
if (task.mUserId != userId) continue;
- if (!taskPackageName.equals(packageName)) continue;
+ if (!task.getBasePackageName().equals(packageName)) continue;
mSupervisor.removeTask(task, true, REMOVE_FROM_RECENTS, "remove-package-task");
}
@@ -859,8 +857,7 @@
if (task.effectiveUid != callingUid) {
continue;
}
- Intent intent = task.getBaseIntent();
- if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) {
+ if (!callingPackage.equals(task.getBasePackageName())) {
continue;
}
AppTaskImpl taskImpl = new AppTaskImpl(mService, task.mTaskId, callingUid);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 699e02e..0bf64ff 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -374,6 +374,13 @@
* determining the order when restoring. */
long mLastTimeMoved;
+ /**
+ * If it is set, the processes belong to the task will be killed when one of its activity
+ * reports that Activity#onDestroy is done and the task no longer contains perceptible
+ * components. This should only be set on a leaf task.
+ */
+ boolean mKillProcessesOnDestroyed;
+
/** If original intent did not allow relinquishing task identity, save that information */
private boolean mNeverRelinquishIdentity = true;
@@ -1325,6 +1332,20 @@
return (topTask != this && topTask != null) ? topTask.getBaseIntent() : null;
}
+ /**
+ * Returns the package name which stands for this task. It is empty string if no activities
+ * have been added to this task.
+ */
+ @NonNull
+ String getBasePackageName() {
+ final Intent intent = getBaseIntent();
+ if (intent == null) {
+ return "";
+ }
+ final ComponentName componentName = intent.getComponent();
+ return componentName != null ? componentName.getPackageName() : "";
+ }
+
/** Returns the first non-finishing activity from the bottom. */
ActivityRecord getRootActivity() {
// TODO: Figure out why we historical ignore relinquish identity for this case...
@@ -1429,14 +1450,22 @@
// Only set this based on the first activity
if (!hadActivity) {
- if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
+ int activityOverrideType =
+ r.getRequestedOverrideConfiguration().windowConfiguration.getActivityType();
+ if (activityOverrideType == ACTIVITY_TYPE_UNDEFINED) {
// Normally non-standard activity type for the activity record will be set when the
// object is created, however we delay setting the standard application type until
// this point so that the task can set the type for additional activities added in
// the else condition below.
- r.setActivityType(ACTIVITY_TYPE_STANDARD);
+ activityOverrideType = activityType != ACTIVITY_TYPE_UNDEFINED ? activityType
+ : ACTIVITY_TYPE_STANDARD;
+ // Set the Activity's requestedOverrideConfiguration directly to reduce
+ // WC#onConfigurationChanged calls since it will be called while setting the
+ // Task's activity type below.
+ r.getRequestedOverrideConfiguration().windowConfiguration.setActivityType(
+ activityOverrideType);
}
- setActivityType(r.getActivityType());
+ setActivityType(activityOverrideType);
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
@@ -3679,6 +3708,9 @@
if (mSharedStartingData != null) {
pw.println(prefix + "mSharedStartingData=" + mSharedStartingData);
}
+ if (mKillProcessesOnDestroyed) {
+ pw.println(prefix + "mKillProcessesOnDestroyed=true");
+ }
pw.print(prefix); pw.print("taskId=" + mTaskId);
pw.println(" rootTaskId=" + getRootTaskId());
pw.print(prefix); pw.println("hasChildPipActivity=" + (mChildPipActivity != null));
@@ -5775,8 +5807,6 @@
final int activityType = getActivityType();
task = new Task.Builder(mAtmService)
.setTaskId(taskId)
- .setActivityType(activityType != ACTIVITY_TYPE_UNDEFINED ? activityType
- : ACTIVITY_TYPE_STANDARD)
.setActivityInfo(info)
.setActivityOptions(options)
.setIntent(intent)
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 6bc9fa4..612fc4b 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2553,13 +2553,18 @@
return task != null && !task.isDragResizing() && super.canStartChangeTransition();
}
- /** Records the starting bounds of the closing organized TaskFragment. */
- void setClosingChangingStartBoundsIfNeeded() {
+ /**
+ * Returns {@code true} if the starting bounds of the closing organized TaskFragment is
+ * recorded. Otherwise, return {@code false}.
+ */
+ boolean setClosingChangingStartBoundsIfNeeded() {
if (isOrganizedTaskFragment() && mDisplayContent != null
&& mDisplayContent.mChangingContainers.remove(this)) {
mDisplayContent.mClosingChangingContainers.put(
this, new Rect(mSurfaceFreezer.mFreezeBounds));
+ return true;
}
+ return false;
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d42a629..520d06d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1336,14 +1336,18 @@
// If we are losing visibility, then a snapshot isn't necessary and we are no-longer
// part of a change transition.
if (!visible) {
+ boolean skipUnfreeze = false;
if (asTaskFragment() != null) {
// If the organized TaskFragment is closing while resizing, we want to keep track of
// its starting bounds to make sure the animation starts at the correct position.
// This should be called before unfreeze() because we record the starting bounds
// in SurfaceFreezer.
- asTaskFragment().setClosingChangingStartBoundsIfNeeded();
+ skipUnfreeze = asTaskFragment().setClosingChangingStartBoundsIfNeeded();
}
- mSurfaceFreezer.unfreeze(getSyncTransaction());
+
+ if (!skipUnfreeze) {
+ mSurfaceFreezer.unfreeze(getSyncTransaction());
+ }
}
WindowContainer parent = getParent();
if (parent != null) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a55c7c1..c599da8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -527,6 +527,16 @@
// everything else on screen). Otherwise, it will be put under always-on-top stacks.
final boolean mAssistantOnTopOfDream;
+ /**
+ * If true, don't relaunch the activity upon receiving a configuration change to transition to
+ * or from the {@link UI_MODE_TYPE_DESK} uiMode, which is sent when docking. The configuration
+ * change will still be sent regardless, only the relaunch is skipped. Apps with desk resources
+ * are exempt from this and will behave like normal, since they may expect the relaunch upon the
+ * desk uiMode change.
+ */
+ @VisibleForTesting
+ boolean mSkipActivityRelaunchWhenDocking;
+
final boolean mLimitedAlphaCompositing;
final int mMaxUiWidth;
@@ -1176,6 +1186,8 @@
com.android.internal.R.bool.config_perDisplayFocusEnabled);
mAssistantOnTopOfDream = context.getResources().getBoolean(
com.android.internal.R.bool.config_assistantOnTopOfDream);
+ mSkipActivityRelaunchWhenDocking = context.getResources()
+ .getBoolean(R.bool.config_skipActivityRelaunchWhenDocking);
mLetterboxConfiguration = new LetterboxConfiguration(
// Using SysUI context to have access to Material colors extracted from Wallpaper.
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 8685723..c34aa2b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -378,8 +378,9 @@
}
void handleAppCrash() {
- for (int i = mActivities.size() - 1; i >= 0; --i) {
- final ActivityRecord r = mActivities.get(i);
+ ArrayList<ActivityRecord> activities = new ArrayList<>(mActivities);
+ for (int i = activities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = activities.get(i);
Slog.w(TAG, " Force finishing activity "
+ r.mActivityComponent.flattenToShortString());
r.detachFromProcess();
diff --git a/services/core/jni/com_android_server_sensor_SensorService.cpp b/services/core/jni/com_android_server_sensor_SensorService.cpp
index a916b64..eb729de 100644
--- a/services/core/jni/com_android_server_sensor_SensorService.cpp
+++ b/services/core/jni/com_android_server_sensor_SensorService.cpp
@@ -55,7 +55,8 @@
void registerProximityActiveListener();
void unregisterProximityActiveListener();
jint registerRuntimeSensor(JNIEnv* env, jint deviceId, jint type, jstring name, jstring vendor,
- jint flags, jobject callback);
+ jfloat maximumRange, jfloat resolution, jfloat power, jint minDelay,
+ jint maxDelay, jint flags, jobject callback);
void unregisterRuntimeSensor(jint handle);
jboolean sendRuntimeSensorEvent(JNIEnv* env, jint handle, jint type, jlong timestamp,
jfloatArray values);
@@ -119,7 +120,9 @@
}
jint NativeSensorService::registerRuntimeSensor(JNIEnv* env, jint deviceId, jint type, jstring name,
- jstring vendor, jint flags, jobject callback) {
+ jstring vendor, jfloat maximumRange,
+ jfloat resolution, jfloat power, jint minDelay,
+ jint maxDelay, jint flags, jobject callback) {
if (mService == nullptr) {
ALOGD("Dropping registerRuntimeSensor, sensor service not available.");
return -1;
@@ -130,6 +133,11 @@
.vendor = env->GetStringUTFChars(vendor, 0),
.version = sizeof(sensor_t),
.type = type,
+ .maxRange = maximumRange,
+ .resolution = resolution,
+ .power = power,
+ .minDelay = minDelay,
+ .maxDelay = maxDelay,
#ifdef __LP64__
.flags = static_cast<uint64_t>(flags),
#else
@@ -299,10 +307,12 @@
}
static jint registerRuntimeSensorNative(JNIEnv* env, jclass, jlong ptr, jint deviceId, jint type,
- jstring name, jstring vendor, jint flags,
- jobject callback) {
+ jstring name, jstring vendor, jfloat maximumRange,
+ jfloat resolution, jfloat power, jint minDelay,
+ jint maxDelay, jint flags, jobject callback) {
auto* service = reinterpret_cast<NativeSensorService*>(ptr);
- return service->registerRuntimeSensor(env, deviceId, type, name, vendor, flags, callback);
+ return service->registerRuntimeSensor(env, deviceId, type, name, vendor, maximumRange,
+ resolution, power, minDelay, maxDelay, flags, callback);
}
static void unregisterRuntimeSensorNative(JNIEnv* env, jclass, jlong ptr, jint handle) {
@@ -324,7 +334,7 @@
{"unregisterProximityActiveListenerNative", "(J)V",
reinterpret_cast<void*>(unregisterProximityActiveListenerNative)},
{"registerRuntimeSensorNative",
- "(JIILjava/lang/String;Ljava/lang/String;IL" RUNTIME_SENSOR_CALLBACK_CLASS ";)I",
+ "(JIILjava/lang/String;Ljava/lang/String;FFFIIIL" RUNTIME_SENSOR_CALLBACK_CLASS ";)I",
reinterpret_cast<void*>(registerRuntimeSensorNative)},
{"unregisterRuntimeSensorNative", "(JI)V",
reinterpret_cast<void*>(unregisterRuntimeSensorNative)},
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 06fe4f0..687c861 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -16,6 +16,7 @@
package com.android.server.credentials;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -31,6 +32,7 @@
import android.os.CancellationSignal;
import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
+import android.service.credentials.PermissionUtils;
import android.util.Log;
import com.android.server.credentials.metrics.ApiName;
@@ -88,7 +90,9 @@
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newCreateRequestInfo(
mRequestId, mClientRequest,
- mClientAppInfo.getPackageName()),
+ mClientAppInfo.getPackageName(),
+ PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
+ Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS)),
providerDataList));
} catch (RemoteException e) {
mChosenProviderFinalPhaseMetric.setUiReturned(false);
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index 9165901..f48fc2c 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -16,6 +16,7 @@
package com.android.server.credentials;
+import android.Manifest;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -28,17 +29,20 @@
import android.credentials.IGetCredentialCallback;
import android.credentials.IPrepareGetCredentialCallback;
import android.credentials.PrepareGetCredentialResponseInternal;
+import android.credentials.ui.GetCredentialProviderData;
import android.credentials.ui.ProviderData;
import android.credentials.ui.RequestInfo;
import android.os.CancellationSignal;
import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
+import android.service.credentials.PermissionUtils;
import android.util.Log;
import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ProviderStatusForMetrics;
import java.util.ArrayList;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -222,30 +226,33 @@
// If all provider responses have been received, we can either need the UI,
// or we need to respond with error. The only other case is the entry being
// selected after the UI has been invoked which has a separate code path.
- if (isUiInvocationNeeded()) {
- if (mIsInitialQuery) {
- try {
- mPrepareGetCredentialCallback.onResponse(
- new PrepareGetCredentialResponseInternal(
- false, null, false, false, getUiIntent()));
- } catch (Exception e) {
- Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
+ if (mIsInitialQuery) {
+ // First time in this state. UI shouldn't be invoked because developer wants to
+ // punt it for later
+ boolean hasQueryCandidatePermission = PermissionUtils.hasPermission(
+ mContext,
+ mClientAppInfo.getPackageName(),
+ Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS);
+ if (isUiInvocationNeeded()) {
+ ArrayList<ProviderData> providerData = getProviderDataForUi();
+ if (!providerData.isEmpty()) {
+ constructPendingResponseAndInvokeCallback(hasQueryCandidatePermission,
+ getCredentialResultTypes(hasQueryCandidatePermission),
+ hasAuthenticationResults(providerData, hasQueryCandidatePermission),
+ hasRemoteResults(providerData, hasQueryCandidatePermission),
+ getUiIntent());
+ } else {
+ constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission);
}
- mIsInitialQuery = false;
} else {
- getProviderDataAndInitiateUi();
+ constructEmptyPendingResponseAndInvokeCallback(hasQueryCandidatePermission);
}
+ mIsInitialQuery = false;
} else {
- if (mIsInitialQuery) {
- try {
- mPrepareGetCredentialCallback.onResponse(
- new PrepareGetCredentialResponseInternal(
- false, null, false, false, null));
- } catch (Exception e) {
- Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
- }
- mIsInitialQuery = false;
- // TODO(273308895): should also clear session here
+ // Not the first time. This could be a result of a user selection leading to a UI
+ // invocation again.
+ if (isUiInvocationNeeded()) {
+ getProviderDataAndInitiateUi();
} else {
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
"No credentials available");
@@ -254,6 +261,68 @@
}
}
+ private void constructPendingResponseAndInvokeCallback(boolean hasPermission,
+ Set<String> credentialTypes,
+ boolean hasAuthenticationResults, boolean hasRemoteResults, PendingIntent uiIntent) {
+ try {
+ mPrepareGetCredentialCallback.onResponse(
+ new PrepareGetCredentialResponseInternal(
+ hasPermission,
+ credentialTypes, hasAuthenticationResults, hasRemoteResults, uiIntent));
+ } catch (RemoteException e) {
+ Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
+ }
+ }
+
+ private void constructEmptyPendingResponseAndInvokeCallback(
+ boolean hasQueryCandidatePermission) {
+ try {
+ mPrepareGetCredentialCallback.onResponse(
+ new PrepareGetCredentialResponseInternal(
+ hasQueryCandidatePermission,
+ /*credentialResultTypes=*/ null,
+ /*hasAuthenticationResults=*/false,
+ /*hasRemoteResults=*/ false,
+ /*pendingIntent=*/ null));
+ } catch (RemoteException e) {
+ Log.e(TAG, "EXCEPTION while mPendingCallback.onResponse", e);
+ }
+ }
+
+ private boolean hasRemoteResults(ArrayList<ProviderData> providerData,
+ boolean hasQueryCandidatePermission) {
+ if (!hasQueryCandidatePermission) {
+ return false;
+ }
+ return providerData.stream()
+ .map(data -> (GetCredentialProviderData) data)
+ .anyMatch(getCredentialProviderData ->
+ getCredentialProviderData.getRemoteEntry() != null);
+ }
+
+ private boolean hasAuthenticationResults(ArrayList<ProviderData> providerData,
+ boolean hasQueryCandidatePermission) {
+ if (!hasQueryCandidatePermission) {
+ return false;
+ }
+ return providerData.stream()
+ .map(data -> (GetCredentialProviderData) data)
+ .anyMatch(getCredentialProviderData ->
+ !getCredentialProviderData.getAuthenticationEntries().isEmpty());
+ }
+
+ @Nullable
+ private Set<String> getCredentialResultTypes(boolean hasQueryCandidatePermission) {
+ if (!hasQueryCandidatePermission) {
+ return null;
+ }
+ return mProviders.values().stream()
+ .map(session -> (ProviderGetSession) session)
+ .flatMap(providerGetSession -> providerGetSession
+ .getCredentialEntryTypes().stream())
+ .collect(Collectors.toSet());
+ }
+
private PendingIntent getUiIntent() {
ArrayList<ProviderData> providerDataList = new ArrayList<>();
for (ProviderSession session : mProviders.values()) {
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index d17e984..7d3c86b 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -47,9 +47,11 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -95,7 +97,7 @@
android.credentials.GetCredentialRequest filteredRequest =
filterOptions(providerInfo.getCapabilities(),
getRequestSession.mClientRequest,
- providerInfo.getComponentName());
+ providerInfo);
if (filteredRequest != null) {
Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
new HashMap<>();
@@ -120,7 +122,8 @@
}
/** Creates a new provider session to be used by the request session. */
- @Nullable public static ProviderGetSession createNewSession(
+ @Nullable
+ public static ProviderGetSession createNewSession(
Context context,
@UserIdInt int userId,
CredentialProviderInfo providerInfo,
@@ -129,7 +132,7 @@
android.credentials.GetCredentialRequest filteredRequest =
filterOptions(providerInfo.getCapabilities(),
getRequestSession.mClientRequest,
- providerInfo.getComponentName());
+ providerInfo);
if (filteredRequest != null) {
Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
new HashMap<>();
@@ -178,12 +181,13 @@
private static android.credentials.GetCredentialRequest filterOptions(
List<String> providerCapabilities,
android.credentials.GetCredentialRequest clientRequest,
- ComponentName componentName
+ CredentialProviderInfo info
) {
List<CredentialOption> filteredOptions = new ArrayList<>();
for (CredentialOption option : clientRequest.getCredentialOptions()) {
if (providerCapabilities.contains(option.getType())
- && isProviderAllowed(option, componentName)) {
+ && isProviderAllowed(option, info.getComponentName())
+ && checkSystemProviderRequirement(option, info.isSystemProvider())) {
Log.i(TAG, "In createProviderRequest - capability found : "
+ option.getType());
filteredOptions.add(option);
@@ -212,6 +216,15 @@
return true;
}
+ private static boolean checkSystemProviderRequirement(CredentialOption option,
+ boolean isSystemProvider) {
+ if (option.isSystemProviderRequired() && !isSystemProvider) {
+ Log.d(TAG, "System provider required, but this service is not a system provider");
+ return false;
+ }
+ return true;
+ }
+
public ProviderGetSession(Context context,
CredentialProviderInfo info,
ProviderInternalCallback<GetCredentialResponse> callbacks,
@@ -327,6 +340,11 @@
}
}
+ @NonNull
+ protected Set<String> getCredentialEntryTypes() {
+ return mProviderResponseDataHandler.getCredentialEntryTypes();
+ }
+
@Override // Call from request session to data to be shown on the UI
@Nullable
protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException {
@@ -564,6 +582,9 @@
private final Map<String, Pair<Action, AuthenticationEntry>> mUiAuthenticationEntries =
new HashMap<>();
+ @NonNull
+ private final Set<String> mCredentialEntryTypes = new HashSet<>();
+
@Nullable
private Pair<String, Pair<RemoteEntry, Entry>> mUiRemoteEntry = null;
@@ -596,6 +617,7 @@
id, credentialEntry.getSlice(),
setUpFillInIntent(credentialEntry.getBeginGetCredentialOptionId()));
mUiCredentialEntries.put(id, new Pair<>(credentialEntry, entry));
+ mCredentialEntryTypes.add(credentialEntry.getType());
}
public void addAction(Action action) {
@@ -692,6 +714,11 @@
&& response.getRemoteCredentialEntry() == null;
}
+ @NonNull
+ public Set<String> getCredentialEntryTypes() {
+ return mCredentialEntryTypes;
+ }
+
@Nullable
public Action getAuthenticationAction(String entryKey) {
return mUiAuthenticationEntries.get(entryKey) == null ? null :
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 0aa080b..d4ad65e 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -236,16 +236,26 @@
}
void getProviderDataAndInitiateUi() {
+ ArrayList<ProviderData> providerDataList = getProviderDataForUi();
+ if (!providerDataList.isEmpty()) {
+ Log.i(TAG, "provider list not empty about to initiate ui");
+ MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter);
+ launchUiWithProviderData(providerDataList);
+ }
+ }
+
+ @NonNull
+ protected ArrayList<ProviderData> getProviderDataForUi() {
Log.i(TAG, "In getProviderDataAndInitiateUi");
Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size());
+ ArrayList<ProviderData> providerDataList = new ArrayList<>();
if (isSessionCancelled()) {
MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter);
finishSession(/*propagateCancellation=*/true);
- return;
+ return providerDataList;
}
- ArrayList<ProviderData> providerDataList = new ArrayList<>();
for (ProviderSession session : mProviders.values()) {
Log.i(TAG, "preparing data for : " + session.getComponentName());
ProviderData providerData = session.prepareUiData();
@@ -254,11 +264,7 @@
providerDataList.add(providerData);
}
}
- if (!providerDataList.isEmpty()) {
- Log.i(TAG, "provider list not empty about to initiate ui");
- MetricUtilities.logApiCalled(mProviders, ++mSequenceCounter);
- launchUiWithProviderData(providerDataList);
- }
+ return providerDataList;
}
protected void collectFinalPhaseMetricStatus(boolean hasException,
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index f86e464..44ec26e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -19,9 +19,11 @@
import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.OP_COARSE_LOCATION;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
+import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_READ_SMS;
import static android.app.AppOpsManager.OP_WIFI_SCAN;
import static android.app.AppOpsManager.OP_WRITE_SMS;
+import static android.os.UserHandle.getUserId;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -33,12 +35,15 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
+import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
import android.app.AppOpsManager.PackageOps;
import android.content.ContentResolver;
@@ -48,14 +53,19 @@
import android.os.HandlerThread;
import android.os.Process;
import android.provider.Settings;
+import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerLocal;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import org.junit.After;
@@ -67,6 +77,7 @@
import java.io.File;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
/**
* Unit tests for AppOpsService. Covers functionality that is difficult to test using CTS tests
@@ -133,6 +144,7 @@
mMockingSession = mockitoSession()
.strictness(Strictness.LENIENT)
.spyStatic(LocalServices.class)
+ .spyStatic(LocalManagerRegistry.class)
.spyStatic(Settings.Global.class)
.startMocking();
@@ -152,6 +164,23 @@
doReturn(mockPackageManagerInternal).when(
() -> LocalServices.getService(PackageManagerInternal.class));
+ PackageManagerLocal mockPackageManagerLocal = mock(PackageManagerLocal.class);
+ PackageManagerLocal.UnfilteredSnapshot mockUnfilteredSnapshot =
+ mock(PackageManagerLocal.UnfilteredSnapshot.class);
+ PackageState mockMyPS = mock(PackageState.class);
+ ArrayMap<String, PackageState> packageStates = new ArrayMap<>();
+ packageStates.put(sMyPackageName, mockMyPS);
+ when(mockMyPS.getAppId()).thenReturn(mMyUid);
+ when(mockUnfilteredSnapshot.getPackageStates()).thenReturn(packageStates);
+ when(mockPackageManagerLocal.withUnfilteredSnapshot()).thenReturn(mockUnfilteredSnapshot);
+ doReturn(mockPackageManagerLocal).when(
+ () -> LocalManagerRegistry.getManager(PackageManagerLocal.class));
+
+ UserManagerInternal mockUserManagerInternal = mock(UserManagerInternal.class);
+ when(mockUserManagerInternal.getUserIds()).thenReturn(new int[] {getUserId(mMyUid)});
+ doReturn(mockUserManagerInternal).when(
+ () -> LocalServices.getService(UserManagerInternal.class));
+
// Mock behavior to use specific Settings.Global.APPOP_HISTORY_PARAMETERS
doReturn(null).when(() -> Settings.Global.getString(any(ContentResolver.class),
eq(Settings.Global.APPOP_HISTORY_PARAMETERS)));
@@ -337,6 +366,25 @@
assertThat(getLoggedOps()).isNull();
}
+ @Test
+ public void testUidStateInitializationDoesntClearState() throws InterruptedException {
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
+ mAppOpsService.initializeUidStates();
+ List<PackageOps> ops = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName,
+ new int[]{OP_READ_SMS});
+ assertNotNull(ops);
+ for (int i = 0; i < ops.size(); i++) {
+ List<OpEntry> opEntries = ops.get(i).getOps();
+ for (int j = 0; j < opEntries.size(); j++) {
+ Map<String, AppOpsManager.AttributedOpEntry> attributedOpEntries = opEntries.get(
+ j).getAttributedOpEntries();
+ assertNotEquals(-1, attributedOpEntries.get(null)
+ .getLastAccessTime(OP_FLAG_SELF));
+ }
+ }
+ }
+
private List<PackageOps> getLoggedOps() {
return mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, null /* all ops */);
}
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 ba70c584..8f38f25 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -340,6 +340,50 @@
/**
* Confirm that
* {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
+ * returns a job that is no longer allowed to run as a user-initiated job after it hits
+ * the cumulative execution limit.
+ */
+ @Test
+ public void testGetRescheduleJobForFailure_cumulativeExecution() {
+ JobStatus originalJob = createJobStatus("testGetRescheduleJobForFailure",
+ createJobInfo()
+ .setUserInitiated(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ assertTrue(originalJob.shouldTreatAsUserInitiatedJob());
+
+ // Cumulative time = 0
+ JobStatus rescheduledJob = mService.getRescheduleJobForFailureLocked(originalJob,
+ JobParameters.STOP_REASON_UNDEFINED,
+ JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
+
+ // Cumulative time = 50% of limit
+ rescheduledJob.incrementCumulativeExecutionTime(
+ mService.mConstants.RUNTIME_CUMULATIVE_UI_LIMIT_MS / 2);
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_UNDEFINED,
+ JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
+
+ // Cumulative time = 99.999999% of limit
+ rescheduledJob.incrementCumulativeExecutionTime(
+ mService.mConstants.RUNTIME_CUMULATIVE_UI_LIMIT_MS / 2 - 1);
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_UNDEFINED,
+ JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
+
+ // Cumulative time = 100+% of limit
+ rescheduledJob.incrementCumulativeExecutionTime(2);
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.STOP_REASON_UNDEFINED,
+ JobParameters.INTERNAL_STOP_REASON_UNKNOWN);
+ assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
+ }
+
+ /**
+ * Confirm that
+ * {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int, int)}
* returns a job with the correct delay and deadline constraints.
*/
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index a3ae834..2d8fa1b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -1318,6 +1318,6 @@
private static JobStatus createJobStatus(JobInfo.Builder job, int uid,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
return new JobStatus(job.build(), uid, null, -1, 0, null, null,
- earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, null, 0, 0);
+ earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis, 0, 0, 0, null, 0, 0);
}
}
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 4b19bbb..7ae6a2d 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
@@ -493,21 +493,21 @@
JobStatus js = createJobStatus("time", jb);
js = new JobStatus(
js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 0,
- FROZEN_TIME, FROZEN_TIME);
+ 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 */ 2, /* numSystemStops */ 1,
- FROZEN_TIME, FROZEN_TIME);
+ 0, 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 */ 0, /* numSystemStops */ 10,
- FROZEN_TIME, FROZEN_TIME);
+ 0, FROZEN_TIME, FROZEN_TIME);
assertEquals(mFcConfig.MAX_RESCHEDULED_DEADLINE_MS,
mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0));
}
@@ -662,11 +662,11 @@
JobStatus js = createJobStatus("time", jb);
js = new JobStatus(
js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1, /* numSystemStops */ 0,
- FROZEN_TIME, FROZEN_TIME);
+ 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);
+ 0, 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 b076ab4..df6f999 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
@@ -374,28 +374,28 @@
int numFailures = 1;
int numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
// 2+ failures, priority should be lowered as much as possible.
numFailures = 2;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
numFailures = 8;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 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);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
}
@@ -412,44 +412,44 @@
int numFailures = 1;
int numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
// Failures in [2,4), priority should be lowered slightly.
numFailures = 2;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
numFailures = 3;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
// Failures in [4,6), priority should be lowered more.
numFailures = 4;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
// 6+ failures, priority should be lowered as much as possible.
numFailures = 6;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
numFailures = 12;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 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);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
}
@@ -470,32 +470,32 @@
int numFailures = 1;
int numSystemStops = 0;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
numFailures = 4;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
numFailures = 5;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
// 6+ failures, priority should be lowered as much as possible.
numFailures = 6;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
numFailures = 12;
job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
- numSystemStops, 0, 0);
+ numSystemStops, 0, 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);
+ numSystemStops, 0, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
}
@@ -515,16 +515,49 @@
job = createJobStatus(jobInfo);
assertTrue(job.shouldTreatAsUserInitiatedJob());
+ }
+
+ @Test
+ public void testShouldTreatAsUserInitiated_userDemoted() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setUserInitiated(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+
+ assertTrue(job.shouldTreatAsUserInitiatedJob());
JobStatus rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
- 0, 0, 0, 0);
+ 0, 0, 0, 0, 0);
assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
assertFalse(job.shouldTreatAsUserInitiatedJob());
rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
- 0, 0, 0, 0);
+ 0, 0, 0, 0, 0);
+ assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
+ }
+
+ @Test
+ public void testShouldTreatAsUserInitiated_systemDemoted() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setUserInitiated(true)
+ .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+
+ assertTrue(job.shouldTreatAsUserInitiatedJob());
+
+ JobStatus rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
+ 0, 0, 0, 0, 0);
+ assertTrue(rescheduledJob.shouldTreatAsUserInitiatedJob());
+
+ job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_SYSTEM_UIJ);
+ assertFalse(job.shouldTreatAsUserInitiatedJob());
+
+ rescheduledJob = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME,
+ 0, 0, 0, 0, 0);
assertFalse(rescheduledJob.shouldTreatAsUserInitiatedJob());
}
@@ -1082,7 +1115,7 @@
final JobInfo job = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
return new JobStatus(job, 0, null, -1, 0, null, null, earliestRunTimeElapsedMillis,
- latestRunTimeElapsedMillis, 0, 0, null, 0, 0);
+ latestRunTimeElapsedMillis, 0, 0, 0, null, 0, 0);
}
private static JobStatus createJobStatus(JobInfo job) {
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 a9b68eb..77723d7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
@@ -150,7 +150,7 @@
mEconomicPolicy.getMaxSatiatedBalance(0, pkgExempted));
final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
+ when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
@@ -184,7 +184,7 @@
when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
+ when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
assertEquals(arcToCake(8), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
assertEquals(arcToCake(7), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
}
@@ -212,7 +212,7 @@
when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
+ when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
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 d66e74a..c5fdb6f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
@@ -207,7 +207,7 @@
when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
+ when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
assertEquals(arcToCake(10), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
}
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 22c7310..d41c93ba2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
@@ -150,7 +150,7 @@
mEconomicPolicy.getMaxSatiatedBalance(0, pkgExempted));
final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
+ when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
@@ -201,7 +201,7 @@
when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
assertEquals(arcToCake(6), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
+ when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
assertEquals(arcToCake(4), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
final String pkgUpdater = "com.pkg.updater";
@@ -235,7 +235,7 @@
when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(eq(pkgHeadlessSystemApp))).thenReturn(true);
+ when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
final String pkgUpdater = "com.pkg.updater";
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
index 1259d71..aea8b86 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
@@ -81,7 +82,8 @@
@Test
public void createSensor_invalidHandle_throwsException() {
doReturn(/* handle= */0).when(mSensorManagerInternalMock).createRuntimeSensor(
- anyInt(), anyInt(), anyString(), anyString(), anyInt(), any());
+ anyInt(), anyInt(), anyString(), anyString(), anyFloat(), anyFloat(), anyFloat(),
+ anyInt(), anyInt(), anyInt(), any());
Throwable thrown = assertThrows(
RuntimeException.class,
@@ -138,7 +140,8 @@
private void doCreateSensorSuccessfully() {
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
- anyInt(), anyInt(), anyString(), anyString(), anyInt(), any());
+ anyInt(), anyInt(), anyString(), anyString(), anyFloat(), anyFloat(), anyFloat(),
+ anyInt(), anyInt(), anyInt(), any());
assertThat(mSensorController.createSensor(mSensorToken, mVirtualSensorConfig))
.isEqualTo(SENSOR_HANDLE);
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 339ccd8..a4a3e36 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -536,7 +536,8 @@
.build();
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
- anyInt(), anyInt(), anyString(), anyString(), anyInt(), any());
+ anyInt(), anyInt(), anyString(), anyString(), anyFloat(), anyFloat(), anyFloat(),
+ anyInt(), anyInt(), anyInt(), any());
mDeviceImpl.close();
mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
diff --git a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
index 56d01b0..5e7dc33 100644
--- a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java
@@ -21,6 +21,7 @@
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
+import android.os.DeviceIdleManager;
import android.test.AndroidTestCase;
import com.android.server.job.MockBiasJobService.TestEnvironment;
@@ -48,6 +49,7 @@
sJobServiceComponent = new ComponentName(getContext(), MockBiasJobService.class);
mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
mJobScheduler.cancelAll();
+ getContext().getSystemService(DeviceIdleManager.class).endIdle("BiasSchedulingTest");
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 236c74f..6bfd93b 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -478,6 +478,7 @@
0 /* sourceUserId */, 0, "someNamespace", "someTag",
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
+ 0 /* cumulativeExecutionTime */,
persistedExecutionTimesUTC, 0 /* innerFlag */, 0 /* dynamicConstraints */);
mTaskStoreUnderTest.add(js);
@@ -515,6 +516,21 @@
}
@Test
+ public void testCumulativeExecutionTimePersisted() throws Exception {
+ JobInfo ji = new Builder(53, mComponent).setPersisted(true).build();
+ final JobStatus js = JobStatus.createFromJobInfo(ji, SOME_UID, null, -1, null, null);
+ js.incrementCumulativeExecutionTime(1234567890);
+ mTaskStoreUnderTest.add(js);
+ waitForPendingIo();
+
+ final JobSet jobStatusSet = new JobSet();
+ mTaskStoreUnderTest.readJobMapFromDisk(jobStatusSet, true);
+ JobStatus loaded = jobStatusSet.getAllJobs().iterator().next();
+ assertEquals("Cumulative execution time not correctly persisted.",
+ 1234567890, loaded.getCumulativeExecutionTimeMs());
+ }
+
+ @Test
public void testNamespacePersisted() throws Exception {
final String namespace = "my.test.namespace";
JobInfo.Builder b = new Builder(93, mComponent)
@@ -853,6 +869,9 @@
compareTimestampsSubjectToIoLatency("Late run-times not the same after read.",
expected.getLatestRunTimeElapsed(), actual.getLatestRunTimeElapsed());
+ assertEquals(expected.getCumulativeExecutionTimeMs(),
+ actual.getCumulativeExecutionTimeMs());
+
assertEquals(expected.hasWorkLocked(), actual.hasWorkLocked());
if (expected.hasWorkLocked()) {
List<JobWorkItem> allWork = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 1a635a9e..b8a21ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -45,6 +45,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -491,6 +492,62 @@
}
@Test
+ public void testDeskModeChange_doesNotRelaunch() throws RemoteException {
+ mWm.mSkipActivityRelaunchWhenDocking = true;
+
+ final ActivityRecord activity = createActivityWithTask();
+ // The activity will already be relaunching out of the gate, finish the relaunch so we can
+ // test properly.
+ activity.finishRelaunching();
+ // Clear out any calls to scheduleTransaction from launching the activity.
+ reset(mAtm.getLifecycleManager());
+
+ final Task task = activity.getTask();
+ activity.setState(RESUMED, "Testing");
+
+ // Send a desk UI mode config update.
+ final Configuration newConfig = new Configuration(task.getConfiguration());
+ newConfig.uiMode |= UI_MODE_TYPE_DESK;
+ task.onRequestedOverrideConfigurationChanged(newConfig);
+ ensureActivityConfiguration(activity);
+
+ // The activity shouldn't start relaunching since it doesn't have any desk resources.
+ assertFalse(activity.isRelaunching());
+
+ // The configuration change is still sent to the activity, even if it doesn't relaunch.
+ final ActivityConfigurationChangeItem expected =
+ ActivityConfigurationChangeItem.obtain(newConfig);
+ verify(mAtm.getLifecycleManager()).scheduleTransaction(
+ eq(activity.app.getThread()), eq(activity.token), eq(expected));
+ }
+
+ @Test
+ public void testDeskModeChange_relaunchesWithDeskResources() {
+ mWm.mSkipActivityRelaunchWhenDocking = true;
+
+ final ActivityRecord activity = createActivityWithTask();
+ // The activity will already be relaunching out of the gate, finish the relaunch so we can
+ // test properly.
+ activity.finishRelaunching();
+
+ // Activities with desk resources should get relaunched when a UI_MODE_TYPE_DESK change
+ // comes in.
+ doReturn(true).when(activity).hasDeskResources();
+
+ final Task task = activity.getTask();
+ activity.setState(RESUMED, "Testing");
+
+ // Send a desk UI mode config update.
+ final Configuration newConfig = new Configuration(task.getConfiguration());
+ newConfig.uiMode |= UI_MODE_TYPE_DESK;
+ task.onRequestedOverrideConfigurationChanged(newConfig);
+ ensureActivityConfiguration(activity);
+
+ // The activity will relaunch since it has desk resources.
+ assertTrue(activity.isRelaunching());
+ }
+
+ @Test
public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 3ae1317..12e4825 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -826,6 +826,33 @@
assertTrue(mController.shouldSendFakeFocus());
}
+ @Test
+ public void testgetFixedOrientationLetterboxAspectRatio_splitScreenAspectEnabled() {
+ doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration)
+ .isCameraCompatTreatmentEnabled(anyBoolean());
+ doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration)
+ .isCameraCompatSplitScreenAspectRatioEnabled();
+ doReturn(false).when(mActivity.mWmService.mLetterboxConfiguration)
+ .getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox();
+ doReturn(1.5f).when(mActivity.mWmService.mLetterboxConfiguration)
+ .getFixedOrientationLetterboxAspectRatio();
+
+ // Recreate DisplayContent with DisplayRotationCompatPolicy
+ mActivity = setUpActivityWithComponent();
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertEquals(mController.getFixedOrientationLetterboxAspectRatio(
+ mActivity.getParent().getConfiguration()), 1.5f, /* delta */ 0.01);
+
+ spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
+ doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
+ .isTreatmentEnabledForActivity(eq(mActivity));
+
+ assertEquals(mController.getFixedOrientationLetterboxAspectRatio(
+ mActivity.getParent().getConfiguration()), mController.getSplitScreenAspectRatio(),
+ /* delta */ 0.01);
+ }
+
private void mockThatProperty(String propertyName, boolean value) throws Exception {
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
/* className */ "");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 12f9a9e..9ebc730 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1032,6 +1032,17 @@
fail("Expected com.android.pkg1 tasks to be removed");
}
}
+
+ // If the task has a non-stopped activity, the removal will wait for its onDestroy.
+ final Task task = tasks.get(0);
+ final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).build();
+ top.lastVisibleTime = 123;
+ top.setState(ActivityRecord.State.RESUMED, "test");
+ mRecentTasks.removeTasksByPackageName(task.getBasePackageName(), TEST_USER_0_ID);
+ assertTrue(task.mKillProcessesOnDestroyed);
+ top.setState(ActivityRecord.State.DESTROYING, "test");
+ top.destroyed("test");
+ assertFalse(task.mKillProcessesOnDestroyed);
}
@Test
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 582d7d8..d7bf4b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1415,6 +1415,8 @@
final Transition.ChangeInfo activity1ChangeInfo = closeTransition.mChanges.get(activity1);
assertNotNull(activity1ChangeInfo);
assertTrue(activity1ChangeInfo.hasChanged());
+ // No need to wait for the activity in transient hide task.
+ assertTrue(activity1.isSyncFinished());
activity1.setVisibleRequested(false);
activity2.setVisibleRequested(true);
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index ba3a192..5eace54 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -23,6 +23,9 @@
import android.os.Parcel;
import android.telephony.cdma.CdmaCellLocation;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
+
import java.util.Objects;
/**
@@ -242,8 +245,8 @@
.append(":{ mNetworkId=").append(mNetworkId)
.append(" mSystemId=").append(mSystemId)
.append(" mBasestationId=").append(mBasestationId)
- .append(" mLongitude=").append(mLongitude)
- .append(" mLatitude=").append(mLatitude)
+ .append(" mLongitude=").append(Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mLongitude))
+ .append(" mLatitude=").append(Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mLatitude))
.append(" mAlphaLong=").append(mAlphaLong)
.append(" mAlphaShort=").append(mAlphaShort)
.append("}").toString();
diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
index d808cab..d4cb5ac 100644
--- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java
+++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
@@ -21,6 +21,9 @@
import android.os.Bundle;
import android.telephony.CellLocation;
+import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
+
/**
* Represents the cell location on a CDMA phone.
*
@@ -197,8 +200,8 @@
@Override
public String toString() {
return "[" + this.mBaseStationId + ","
- + this.mBaseStationLatitude + ","
- + this.mBaseStationLongitude + ","
+ + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, this.mBaseStationLatitude) + ","
+ + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, this.mBaseStationLongitude) + ","
+ this.mSystemId + ","
+ this.mNetworkId + "]";
}
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 33c86d8..4c37f7d 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -398,7 +398,11 @@
ImsService.this.disableImsForSubscription(slotId, subId), "disableIms");
}
-
+ @Override
+ public void resetIms(int slotId, int subId) {
+ executeMethodAsync(() ->
+ ImsService.this.resetImsInternal(slotId, subId), "resetIms");
+ }
};
private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@@ -634,6 +638,14 @@
}
}
+ private void resetImsInternal(int slotId, int subId) {
+ try {
+ resetIms(slotId);
+ } catch (UnsupportedOperationException e) {
+ disableImsForSubscription(slotId, subId);
+ }
+ }
+
/**
* When called, provide the {@link ImsFeatureConfiguration} that this {@link ImsService}
* currently supports. This will trigger the framework to set up the {@link ImsFeature}s that
@@ -751,6 +763,19 @@
}
/**
+ * The framework has reset IMS for the slot specified. The ImsService must deregister
+ * and release all resources for IMS. After resetIms is called, either
+ * {@link #enableImsForSubscription(int, int)} or {@link #disableImsForSubscription(int, int)}
+ * will be called for the same slotId.
+ *
+ * @param slotId The slot ID that IMS will be reset for.
+ * @hide
+ */
+ public void resetIms(int slotId) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* When called, the framework is requesting that a new {@link MmTelFeature} is created for the
* specified subscription.
*
diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
index ae6166f..fdf43a5 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
@@ -47,4 +47,5 @@
ISipTransport getSipTransport(int slotId);
oneway void enableIms(int slotId, int subId);
oneway void disableIms(int slotId, int subId);
+ oneway void resetIms(int slotId, int subId);
}
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml
index 2a0a2c7..4487cef 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/ApkVerityTest/AndroidTest.xml
@@ -16,6 +16,11 @@
<configuration description="APK fs-verity integration/regression test">
<option name="test-suite-tag" value="apct" />
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
+ <!-- fs-verity is required since R/30 -->
+ <option name="vsr-min-api-level" value="30" />
+ </object>
+
<!-- This test requires root to write against block device. -->
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />