diff options
228 files changed, 5240 insertions, 3791 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 930415fcd8fd..b7a3f1083176 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -59,6 +59,12 @@ import java.util.Objects; * constraint on the JobInfo object that you are creating. Otherwise, the builder would throw an * exception when building. From Android version {@link Build.VERSION_CODES#Q} and onwards, it is * valid to schedule jobs with no constraints. + * <p> In Android version {@link Build.VERSION_CODES#LOLLIPOP}, jobs had a maximum execution time + * of one minute. Starting with Android version {@link Build.VERSION_CODES#M} and ending with + * Android version {@link Build.VERSION_CODES#R}, jobs had a maximum execution time of 10 minutes. + * Starting from Android version {@link Build.VERSION_CODES#S}, jobs will still be stopped after + * 10 minutes if the system is busy or needs the resources, but if not, jobs may continue running + * longer than 10 minutes. */ public class JobInfo implements Parcelable { private static String TAG = "JobInfo"; @@ -1461,11 +1467,13 @@ public class JobInfo implements Parcelable { * possible with stronger guarantees than regular jobs. These "expedited" jobs will: * <ol> * <li>Run as soon as possible</li> - * <li>Be exempted from Doze and battery saver restrictions</li> + * <li>Be less restricted during Doze and battery saver</li> * <li>Have network access</li> - * <li>Less likely to be killed than regular jobs</li> + * <li>Be less likely to be killed than regular jobs</li> + * <li>Be subject to background location throttling</li> * </ol> * + * <p> * Since these jobs have stronger guarantees than regular jobs, they will be subject to * stricter quotas. As long as an app has available expedited quota, jobs scheduled with * this set to true will run with these guarantees. If an app has run out of available @@ -1475,9 +1483,18 @@ public class JobInfo implements Parcelable { * will immediately return {@link JobScheduler#RESULT_FAILURE} if the app does not have * available quota (and the job will not be successfully scheduled). * + * <p> * Expedited jobs may only set network, storage-not-low, and persistence constraints. * No other constraints are allowed. * + * <p> + * Assuming all constraints remain satisfied (including ideal system load conditions), + * expedited jobs are guaranteed to have a minimum allowed runtime of 1 minute. If your + * app has remaining expedited job quota, then the expedited job <i>may</i> potentially run + * longer until remaining quota is used up. Just like with regular jobs, quota is not + * consumed while the app is on top and visible to the user. + * + * <p> * Note: Even though expedited jobs are meant to run as soon as possible, they may be * deferred if the system is under heavy load or requested constraints are not satisfied. * diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java index 283e933e0fa9..df0e157abc6a 100644 --- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java +++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java @@ -87,7 +87,7 @@ public class PowerWhitelistManager { * The list of temp allowlist types. * @hide */ - @IntDef(flag = true, prefix = { "TEMPORARY_ALLOW_TYPE_" }, value = { + @IntDef(flag = true, prefix = { "TEMPORARY_ALLOWLIST_TYPE_" }, value = { TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED, }) diff --git a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java index b7e8cf6e3fc8..7f191d4a306a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java +++ b/apex/jobscheduler/service/java/com/android/server/job/GrantedUriPermissions.java @@ -26,6 +26,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.util.proto.ProtoOutputStream; + import com.android.server.LocalServices; import com.android.server.uri.UriGrantsManagerInternal; @@ -144,13 +145,13 @@ public final class GrantedUriPermissions { } // Dumpsys infrastructure - public void dump(PrintWriter pw, String prefix) { - pw.print(prefix); pw.print("mGrantFlags=0x"); pw.print(Integer.toHexString(mGrantFlags)); + public void dump(PrintWriter pw) { + pw.print("mGrantFlags=0x"); pw.print(Integer.toHexString(mGrantFlags)); pw.print(" mSourceUserId="); pw.println(mSourceUserId); - pw.print(prefix); pw.print("mTag="); pw.println(mTag); - pw.print(prefix); pw.print("mPermissionOwner="); pw.println(mPermissionOwner); + pw.print("mTag="); pw.println(mTag); + pw.print("mPermissionOwner="); pw.println(mPermissionOwner); for (int i = 0; i < mUris.size(); i++) { - pw.print(prefix); pw.print("#"); pw.print(i); pw.print(": "); + pw.print("#"); pw.print(i); pw.print(": "); pw.println(mUris.get(i)); } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java index 164781a250b7..af9771553063 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -20,6 +20,7 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.UserSwitchObserver; @@ -80,6 +81,8 @@ class JobConcurrencyManager { static final int WORK_TYPE_BGUSER = 1 << 3; @VisibleForTesting static final int NUM_WORK_TYPES = 4; + private static final int ALL_WORK_TYPES = + WORK_TYPE_TOP | WORK_TYPE_EJ | WORK_TYPE_BG | WORK_TYPE_BGUSER; @IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = { WORK_TYPE_NONE, @@ -92,6 +95,23 @@ class JobConcurrencyManager { public @interface WorkType { } + private static String workTypeToString(@WorkType int workType) { + switch (workType) { + case WORK_TYPE_NONE: + return "NONE"; + case WORK_TYPE_TOP: + return "TOP"; + case WORK_TYPE_EJ: + return "EJ"; + case WORK_TYPE_BG: + return "BG"; + case WORK_TYPE_BGUSER: + return "BGUSER"; + default: + return "WORK(" + workType + ")"; + } + } + private final Object mLock; private final JobSchedulerService mService; private final Context mContext; @@ -182,10 +202,16 @@ class JobConcurrencyManager { int[] mRecycledWorkTypeForContext = new int[MAX_JOB_CONTEXTS_COUNT]; + String[] mRecycledPreemptReasonForContext = new String[MAX_JOB_CONTEXTS_COUNT]; + + String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT]; + private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>(); private final WorkCountTracker mWorkCountTracker = new WorkCountTracker(); + private WorkTypeConfig mWorkTypeConfig = CONFIG_LIMITS_SCREEN_OFF.normal; + /** Wait for this long after screen off before adjusting the job concurrency. */ private long mScreenOffAdjustmentDelayMs = DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS; @@ -353,23 +379,22 @@ class JobConcurrencyManager { final WorkConfigLimitsPerMemoryTrimLevel workConfigs = mEffectiveInteractiveState ? CONFIG_LIMITS_SCREEN_ON : CONFIG_LIMITS_SCREEN_OFF; - WorkTypeConfig workTypeConfig; switch (mLastMemoryTrimLevel) { case ProcessStats.ADJ_MEM_FACTOR_MODERATE: - workTypeConfig = workConfigs.moderate; + mWorkTypeConfig = workConfigs.moderate; break; case ProcessStats.ADJ_MEM_FACTOR_LOW: - workTypeConfig = workConfigs.low; + mWorkTypeConfig = workConfigs.low; break; case ProcessStats.ADJ_MEM_FACTOR_CRITICAL: - workTypeConfig = workConfigs.critical; + mWorkTypeConfig = workConfigs.critical; break; default: - workTypeConfig = workConfigs.normal; + mWorkTypeConfig = workConfigs.normal; break; } - mWorkCountTracker.setConfig(workTypeConfig); + mWorkCountTracker.setConfig(mWorkTypeConfig); } /** @@ -401,13 +426,20 @@ class JobConcurrencyManager { boolean[] slotChanged = mRecycledSlotChanged; int[] preferredUidForContext = mRecycledPreferredUidForContext; int[] workTypeForContext = mRecycledWorkTypeForContext; + String[] preemptReasonForContext = mRecycledPreemptReasonForContext; + String[] shouldStopJobReason = mRecycledShouldStopJobReason; updateCounterConfigLocked(); // Reset everything since we'll re-evaluate the current state. mWorkCountTracker.resetCounts(); + // Update the priorities of jobs that aren't running, and also count the pending work types. + // Do this before the following loop to hopefully reduce the cost of + // shouldStopRunningJobLocked(). + updateNonRunningPriorities(pendingJobs, true); + for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { - final JobServiceContext js = mService.mActiveServices.get(i); + final JobServiceContext js = activeServices.get(i); final JobStatus status = js.getRunningJobLocked(); if ((contextIdToJobMap[i] = status) != null) { @@ -417,14 +449,13 @@ class JobConcurrencyManager { slotChanged[i] = false; preferredUidForContext[i] = js.getPreferredUid(); + preemptReasonForContext[i] = null; + shouldStopJobReason[i] = shouldStopRunningJobLocked(js); } if (DEBUG) { Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial")); } - // Next, update the job priorities, and also count the pending FG / BG jobs. - updateNonRunningPriorities(pendingJobs, true); - mWorkCountTracker.onCountDone(); for (int i = 0; i < pendingJobs.size(); i++) { @@ -434,8 +465,6 @@ class JobConcurrencyManager { continue; } - // TODO(171305774): make sure HPJs aren't pre-empted and add dedicated contexts for them - // Find an available slot for nextPending. The context should be available OR // it should have lowest priority among all running jobs // (sharing the same Uid as nextPending) @@ -444,6 +473,9 @@ class JobConcurrencyManager { int allWorkTypes = getJobWorkTypes(nextPending); int workType = mWorkCountTracker.canJobStart(allWorkTypes); boolean startingJob = false; + String preemptReason = null; + // TODO(141645789): rewrite this to look at empty contexts first so we don't + // unnecessarily preempt for (int j = 0; j < MAX_JOB_CONTEXTS_COUNT; j++) { JobStatus job = contextIdToJobMap[j]; int preferredUid = preferredUidForContext[j]; @@ -464,6 +496,15 @@ class JobConcurrencyManager { continue; } if (job.getUid() != nextPending.getUid()) { + // Maybe stop the job if it has had its day in the sun. + final String reason = shouldStopJobReason[j]; + if (reason != null && mWorkCountTracker.canJobStart(allWorkTypes, + activeServices.get(j).getRunningJobWorkType()) != WORK_TYPE_NONE) { + // Right now, the way the code is set up, we don't need to explicitly + // assign the new job to this context since we'll reassign when the + // preempted job finally stops. + preemptReason = reason; + } continue; } @@ -477,6 +518,7 @@ class JobConcurrencyManager { // the lowest-priority running job minPriorityForPreemption = jobPriority; selectedContextId = j; + preemptReason = "higher priority job found"; // In this case, we're just going to preempt a low priority job, we're not // actually starting a job, so don't set startingJob. } @@ -484,6 +526,7 @@ class JobConcurrencyManager { if (selectedContextId != -1) { contextIdToJobMap[selectedContextId] = nextPending; slotChanged[selectedContextId] = true; + preemptReasonForContext[selectedContextId] = preemptReason; } if (startingJob) { // Increase the counters when we're going to start a job. @@ -509,7 +552,7 @@ class JobConcurrencyManager { + activeServices.get(i).getRunningJobLocked()); } // preferredUid will be set to uid of currently running job. - activeServices.get(i).preemptExecutingJobLocked(); + activeServices.get(i).preemptExecutingJobLocked(preemptReasonForContext[i]); preservePreferredUid = true; } else { final JobStatus pendingJob = contextIdToJobMap[i]; @@ -692,6 +735,91 @@ class JobConcurrencyManager { noteConcurrency(); } + /** + * Returns {@code null} if the job can continue running and a non-null String if the job should + * be stopped. The non-null String details the reason for stopping the job. A job will generally + * be stopped if there similar job types waiting to be run and stopping this job would allow + * another job to run, or if system state suggests the job should stop. + */ + @Nullable + String shouldStopRunningJobLocked(@NonNull JobServiceContext context) { + final JobStatus js = context.getRunningJobLocked(); + if (js == null) { + // This can happen when we try to assign newly found pending jobs to contexts. + return null; + } + + if (context.isWithinExecutionGuaranteeTime()) { + return null; + } + + // Update config in case memory usage has changed significantly. + updateCounterConfigLocked(); + + @WorkType final int workType = context.getRunningJobWorkType(); + + // We're over the minimum guaranteed runtime. Stop the job if we're over config limits or + // there are pending jobs that could replace this one. + if (mRunningJobs.size() > mWorkTypeConfig.getMaxTotal() + || mWorkCountTracker.isOverTypeLimit(workType)) { + return "too many jobs running"; + } + + final List<JobStatus> pendingJobs = mService.mPendingJobs; + final int numPending = pendingJobs.size(); + if (numPending == 0) { + // All quiet. We can let this job run to completion. + return null; + } + + // Only expedited jobs can replace expedited jobs. + if (js.shouldTreatAsExpeditedJob()) { + // Keep fg/bg user distinction. + if (workType == WORK_TYPE_BGUSER) { + // For now, let any bg user job replace a bg user expedited job. + // TODO: limit to ej once we have dedicated bg user ej slots. + if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_BGUSER) > 0) { + return "blocking " + workTypeToString(workType) + " queue"; + } + } else { + if (mWorkCountTracker.getPendingJobCount(WORK_TYPE_EJ) > 0) { + return "blocking " + workTypeToString(workType) + " queue"; + } + } + + if (mPowerManager.isPowerSaveMode()) { + return "battery saver"; + } + if (mPowerManager.isDeviceIdleMode()) { + return "deep doze"; + } + } + + // Easy check. If there are pending jobs of the same work type, then we know that + // something will replace this. + if (mWorkCountTracker.getPendingJobCount(workType) > 0) { + return "blocking " + workTypeToString(workType) + " queue"; + } + + // Harder check. We need to see if a different work type can replace this job. + int remainingWorkTypes = ALL_WORK_TYPES; + for (int i = 0; i < numPending; ++i) { + final JobStatus pending = pendingJobs.get(i); + final int workTypes = getJobWorkTypes(pending); + if ((workTypes & remainingWorkTypes) > 0 + && mWorkCountTracker.canJobStart(workTypes, workType) != WORK_TYPE_NONE) { + return "blocking other pending jobs"; + } + + remainingWorkTypes = remainingWorkTypes & ~workTypes; + if (remainingWorkTypes == 0) { + break; + } + } + + return null; + } + @GuardedBy("mLock") private String printPendingQueueLocked() { StringBuilder s = new StringBuilder("Pending queue: "); @@ -1362,10 +1490,40 @@ class JobConcurrencyManager { return WORK_TYPE_NONE; } + int canJobStart(int workTypes, @WorkType int replacingWorkType) { + final boolean changedNums; + int oldNumRunning = mNumRunningJobs.get(replacingWorkType); + if (replacingWorkType != WORK_TYPE_NONE && oldNumRunning > 0) { + mNumRunningJobs.put(replacingWorkType, oldNumRunning - 1); + // Lazy implementation to avoid lots of processing. Best way would be to go + // through the whole process of adjusting reservations, but the processing cost + // is likely not worth it. + mNumUnspecializedRemaining++; + changedNums = true; + } else { + changedNums = false; + } + + final int ret = canJobStart(workTypes); + if (changedNums) { + mNumRunningJobs.put(replacingWorkType, oldNumRunning); + mNumUnspecializedRemaining--; + } + return ret; + } + + int getPendingJobCount(@WorkType final int workType) { + return mNumPendingJobs.get(workType, 0); + } + int getRunningJobCount(@WorkType final int workType) { return mNumRunningJobs.get(workType, 0); } + boolean isOverTypeLimit(@WorkType final int workType) { + return getRunningJobCount(workType) > mConfigAbsoluteMaxSlots.get(workType); + } + public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java index d05034797f3d..6ffac91d7098 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobPackageTracker.java @@ -25,6 +25,7 @@ import android.app.job.JobParameters; import android.os.UserHandle; import android.text.format.DateFormat; import android.util.ArrayMap; +import android.util.IndentingPrintWriter; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimeUtils; @@ -33,8 +34,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.RingBufferIndices; import com.android.server.job.controllers.JobStatus; -import java.io.PrintWriter; - public final class JobPackageTracker { // We batch every 30 minutes. static final long BATCHING_TIME = 30*60*1000; @@ -294,53 +293,69 @@ public final class JobPackageTracker { } } - void printDuration(PrintWriter pw, long period, long duration, int count, String suffix) { + /** Return {@code true} if text was printed. */ + boolean printDuration(IndentingPrintWriter pw, long period, long duration, int count, + String suffix) { float fraction = duration / (float) period; int percent = (int) ((fraction * 100) + .5f); if (percent > 0) { - pw.print(" "); pw.print(percent); pw.print("% "); pw.print(count); pw.print("x "); pw.print(suffix); + return true; } else if (count > 0) { - pw.print(" "); pw.print(count); pw.print("x "); pw.print(suffix); + return true; } + + return false; } - void dump(PrintWriter pw, String header, String prefix, long now, long nowElapsed, - int filterUid) { + void dump(IndentingPrintWriter pw, String header, long now, long nowElapsed, + int filterAppId) { final long period = getTotalTime(now); - pw.print(prefix); pw.print(header); pw.print(" at "); + pw.print(header); pw.print(" at "); pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartClockTime).toString()); pw.print(" ("); TimeUtils.formatDuration(mStartElapsedTime, nowElapsed, pw); pw.print(") over "); TimeUtils.formatDuration(period, pw); pw.println(":"); + pw.increaseIndent(); + pw.print("Max concurrency: "); + pw.print(mMaxTotalActive); pw.print(" total, "); + pw.print(mMaxFgActive); pw.println(" foreground"); + + pw.println(); final int NE = mEntries.size(); for (int i = 0; i < NE; i++) { int uid = mEntries.keyAt(i); - if (filterUid != -1 && filterUid != UserHandle.getAppId(uid)) { + if (filterAppId != -1 && filterAppId != UserHandle.getAppId(uid)) { continue; } ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i); final int NP = uidMap.size(); for (int j = 0; j < NP; j++) { PackageEntry pe = uidMap.valueAt(j); - pw.print(prefix); pw.print(" "); UserHandle.formatUid(pw, uid); pw.print(" / "); pw.print(uidMap.keyAt(j)); pw.println(":"); - pw.print(prefix); pw.print(" "); - printDuration(pw, period, pe.getPendingTime(now), pe.pendingCount, "pending"); - printDuration(pw, period, pe.getActiveTime(now), pe.activeCount, "active"); - printDuration(pw, period, pe.getActiveTopTime(now), pe.activeTopCount, - "active-top"); + + pw.increaseIndent(); + if (printDuration(pw, period, + pe.getPendingTime(now), pe.pendingCount, "pending")) { + pw.print(" "); + } + if (printDuration(pw, period, + pe.getActiveTime(now), pe.activeCount, "active")) { + pw.print(" "); + } + printDuration(pw, period, + pe.getActiveTopTime(now), pe.activeTopCount, "active-top"); if (pe.pendingNesting > 0 || pe.hadPending) { pw.print(" (pending)"); } @@ -352,7 +367,6 @@ public final class JobPackageTracker { } pw.println(); if (pe.stopReasons.size() > 0) { - pw.print(prefix); pw.print(" "); for (int k = 0; k < pe.stopReasons.size(); k++) { if (k > 0) { pw.print(", "); @@ -364,11 +378,10 @@ public final class JobPackageTracker { } pw.println(); } + pw.decreaseIndent(); } } - pw.print(prefix); pw.print(" Max concurrency: "); - pw.print(mMaxTotalActive); pw.print(" total, "); - pw.print(mMaxFgActive); pw.println(" foreground"); + pw.decreaseIndent(); } private void printPackageEntryState(ProtoOutputStream proto, long fieldId, @@ -520,7 +533,7 @@ public final class JobPackageTracker { return time / (float)period; } - public void dump(PrintWriter pw, String prefix, int filterUid) { + void dump(IndentingPrintWriter pw, int filterAppId) { final long now = sUptimeMillisClock.millis(); final long nowElapsed = sElapsedRealtimeClock.millis(); final DataSet total; @@ -533,11 +546,11 @@ public final class JobPackageTracker { mCurDataSet.addTo(total, now); for (int i = 1; i < mLastDataSets.length; i++) { if (mLastDataSets[i] != null) { - mLastDataSets[i].dump(pw, "Historical stats", prefix, now, nowElapsed, filterUid); + mLastDataSets[i].dump(pw, "Historical stats", now, nowElapsed, filterAppId); pw.println(); } } - total.dump(pw, "Current stats", prefix, now, nowElapsed, filterUid); + total.dump(pw, "Current stats", now, nowElapsed, filterAppId); } public void dump(ProtoOutputStream proto, long fieldId, int filterUid) { @@ -566,17 +579,19 @@ public final class JobPackageTracker { proto.end(token); } - public boolean dumpHistory(PrintWriter pw, String prefix, int filterUid) { + boolean dumpHistory(IndentingPrintWriter pw, int filterAppId) { final int size = mEventIndices.size(); if (size <= 0) { return false; } - pw.println(" Job history:"); + pw.increaseIndent(); + pw.println("Job history:"); + pw.decreaseIndent(); final long now = sElapsedRealtimeClock.millis(); for (int i=0; i<size; i++) { final int index = mEventIndices.indexOf(i); final int uid = mEventUids[index]; - if (filterUid != -1 && filterUid != UserHandle.getAppId(uid)) { + if (filterAppId != -1 && filterAppId != UserHandle.getAppId(uid)) { continue; } final int cmd = mEventCmds[index] & EVENT_CMD_MASK; @@ -591,7 +606,6 @@ public final class JobPackageTracker { case EVENT_STOP_PERIODIC_JOB: label = " STOP-P"; break; default: label = " ??"; break; } - pw.print(prefix); TimeUtils.formatDuration(mEventTimes[index]-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); pw.print(" "); pw.print(label); 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 fdbc0864a59d..ac6eb3229a25 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -339,6 +339,7 @@ public class JobSchedulerService extends com.android.server.SystemService public void onPropertiesChanged(DeviceConfig.Properties properties) { boolean apiQuotaScheduleUpdated = false; boolean concurrencyUpdated = false; + boolean runtimeUpdated = false; for (int controller = 0; controller < mControllers.size(); controller++) { final StateController sc = mControllers.get(controller); sc.prepareForUpdatedConstantsLocked(); @@ -377,6 +378,14 @@ public class JobSchedulerService extends com.android.server.SystemService case Constants.KEY_CONN_PREFETCH_RELAX_FRAC: mConstants.updateConnectivityConstantsLocked(); break; + case Constants.KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS: + case Constants.KEY_RUNTIME_MIN_GUARANTEE_MS: + case Constants.KEY_RUNTIME_MIN_EJ_GUARANTEE_MS: + if (!runtimeUpdated) { + mConstants.updateRuntimeConstantsLocked(); + runtimeUpdated = true; + } + break; default: if (name.startsWith(JobConcurrencyManager.CONFIG_KEY_PREFIX_CONCURRENCY) && !concurrencyUpdated) { @@ -432,6 +441,11 @@ public class JobSchedulerService extends com.android.server.SystemService private static final String KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = "aq_schedule_return_failure"; + private static final String KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS = + "runtime_free_quota_max_limit_ms"; + private static final String KEY_RUNTIME_MIN_GUARANTEE_MS = "runtime_min_guarantee_ms"; + private static final String KEY_RUNTIME_MIN_EJ_GUARANTEE_MS = "runtime_min_ej_guarantee_ms"; + private static final int DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT = 5; private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS; private static final float DEFAULT_HEAVY_USE_FACTOR = .9f; @@ -445,6 +459,12 @@ public class JobSchedulerService extends com.android.server.SystemService private static final long DEFAULT_API_QUOTA_SCHEDULE_WINDOW_MS = MINUTE_IN_MILLIS; private static final boolean DEFAULT_API_QUOTA_SCHEDULE_THROW_EXCEPTION = true; private static final boolean DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = false; + @VisibleForTesting + public static final long DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS = 30 * MINUTE_IN_MILLIS; + @VisibleForTesting + public static final long DEFAULT_RUNTIME_MIN_GUARANTEE_MS = 10 * MINUTE_IN_MILLIS; + @VisibleForTesting + public static final long DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS = 3 * MINUTE_IN_MILLIS; /** * Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early. @@ -509,6 +529,19 @@ public class JobSchedulerService extends com.android.server.SystemService public boolean API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT = DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT; + /** The maximum amount of time we will let a job run for when quota is "free". */ + public long RUNTIME_FREE_QUOTA_MAX_LIMIT_MS = DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; + + /** + * The minimum amount of time we try to guarantee regular jobs will run for. + */ + public long RUNTIME_MIN_GUARANTEE_MS = DEFAULT_RUNTIME_MIN_GUARANTEE_MS; + + /** + * The minimum amount of time we try to guarantee EJs will run for. + */ + public long RUNTIME_MIN_EJ_GUARANTEE_MS = DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS; + private void updateBatchingConstantsLocked() { MIN_READY_NON_ACTIVE_JOBS_COUNT = DeviceConfig.getInt( DeviceConfig.NAMESPACE_JOB_SCHEDULER, @@ -568,6 +601,25 @@ public class JobSchedulerService extends com.android.server.SystemService DEFAULT_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT); } + private void updateRuntimeConstantsLocked() { + DeviceConfig.Properties properties = DeviceConfig.getProperties( + DeviceConfig.NAMESPACE_JOB_SCHEDULER, + KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, + KEY_RUNTIME_MIN_GUARANTEE_MS, KEY_RUNTIME_MIN_EJ_GUARANTEE_MS); + + // Make sure min runtime for regular jobs is at least 10 minutes. + RUNTIME_MIN_GUARANTEE_MS = Math.max(10 * MINUTE_IN_MILLIS, + properties.getLong( + KEY_RUNTIME_MIN_GUARANTEE_MS, DEFAULT_RUNTIME_MIN_GUARANTEE_MS)); + // Make sure min runtime for expedited jobs is at least one minute. + RUNTIME_MIN_EJ_GUARANTEE_MS = Math.max(MINUTE_IN_MILLIS, + properties.getLong( + KEY_RUNTIME_MIN_EJ_GUARANTEE_MS, DEFAULT_RUNTIME_MIN_EJ_GUARANTEE_MS)); + RUNTIME_FREE_QUOTA_MAX_LIMIT_MS = Math.max(RUNTIME_MIN_GUARANTEE_MS, + properties.getLong(KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, + DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)); + } + void dump(IndentingPrintWriter pw) { pw.println("Settings:"); pw.increaseIndent(); @@ -591,6 +643,11 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print(KEY_API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT, API_QUOTA_SCHEDULE_RETURN_FAILURE_RESULT).println(); + pw.print(KEY_RUNTIME_MIN_GUARANTEE_MS, RUNTIME_MIN_GUARANTEE_MS).println(); + pw.print(KEY_RUNTIME_MIN_EJ_GUARANTEE_MS, RUNTIME_MIN_EJ_GUARANTEE_MS).println(); + pw.print(KEY_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, RUNTIME_FREE_QUOTA_MAX_LIMIT_MS) + .println(); + pw.decreaseIndent(); } @@ -1602,7 +1659,7 @@ public class JobSchedulerService extends com.android.server.SystemService * time of the job to be the time of completion (i.e. the time at which this function is * called). * <p>This could be inaccurate b/c the job can run for as long as - * {@link com.android.server.job.JobServiceContext#DEFAULT_EXECUTING_TIMESLICE_MILLIS}, but + * {@link Constants#DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS}, but * will lead to underscheduling at least, rather than if we had taken the last execution time * to be the start of the execution. * @@ -2213,11 +2270,24 @@ public class JobSchedulerService extends com.android.server.SystemService return isComponentUsable(job); } + /** Returns the minimum amount of time we should let this job run before timing out. */ + public long getMinJobExecutionGuaranteeMs(JobStatus job) { + synchronized (mLock) { + if (job.shouldTreatAsExpeditedJob()) { + // Don't guarantee RESTRICTED jobs more than 5 minutes. + return job.getEffectiveStandbyBucket() != RESTRICTED_INDEX + ? mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS + : Math.min(mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS, 5 * MINUTE_IN_MILLIS); + } else { + return mConstants.RUNTIME_MIN_GUARANTEE_MS; + } + } + } + /** Returns the maximum amount of time this job could run for. */ public long getMaxJobExecutionTimeMs(JobStatus job) { synchronized (mLock) { - return Math.min(mQuotaController.getMaxJobExecutionTimeMsLocked(job), - JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS); + return mQuotaController.getMaxJobExecutionTimeMsLocked(job); } } @@ -3021,14 +3091,14 @@ public class JobSchedulerService extends com.android.server.SystemService } void dumpInternal(final IndentingPrintWriter pw, int filterUid) { - final int filterUidFinal = UserHandle.getAppId(filterUid); + final int filterAppId = UserHandle.getAppId(filterUid); final long now = sSystemClock.millis(); final long nowElapsed = sElapsedRealtimeClock.millis(); final long nowUptime = sUptimeMillisClock.millis(); final Predicate<JobStatus> predicate = (js) -> { - return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal - || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal; + return filterAppId == -1 || UserHandle.getAppId(js.getUid()) == filterAppId + || UserHandle.getAppId(js.getSourceUid()) == filterAppId; }; synchronized (mLock) { mConstants.dump(pw); @@ -3041,7 +3111,6 @@ public class JobSchedulerService extends com.android.server.SystemService for (int i = mJobRestrictions.size() - 1; i >= 0; i--) { mJobRestrictions.get(i).dumpConstants(pw); - pw.println(); } pw.println(); @@ -3052,21 +3121,25 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print("Registered "); pw.print(mJobs.size()); pw.println(" jobs:"); + pw.increaseIndent(); + boolean jobPrinted = false; if (mJobs.size() > 0) { final List<JobStatus> jobs = mJobs.mJobSet.getAllJobs(); sortJobs(jobs); for (JobStatus job : jobs) { - pw.print(" JOB #"); job.printUniqueId(pw); pw.print(": "); - pw.println(job.toShortStringExceptUniqueId()); - // Skip printing details if the caller requested a filter if (!predicate.test(job)) { continue; } + jobPrinted = true; + + pw.print("JOB #"); job.printUniqueId(pw); pw.print(": "); + pw.println(job.toShortStringExceptUniqueId()); - job.dump(pw, " ", true, nowElapsed); + pw.increaseIndent(); + job.dump(pw, true, nowElapsed); - pw.print(" Restricted due to:"); + pw.print("Restricted due to:"); final boolean isRestricted = checkIfRestricted(job) != null; if (isRestricted) { for (int i = mJobRestrictions.size() - 1; i >= 0; i--) { @@ -3081,7 +3154,7 @@ public class JobSchedulerService extends com.android.server.SystemService } pw.println("."); - pw.print(" Ready: "); + pw.print("Ready: "); pw.print(isReadyToBeExecutedLocked(job)); pw.print(" (job="); pw.print(job.isReady()); @@ -3098,10 +3171,15 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print(" comp="); pw.print(isComponentUsable(job)); pw.println(")"); + + pw.decreaseIndent(); } - } else { - pw.println(" None."); } + if (!jobPrinted) { + pw.println("None."); + } + pw.decreaseIndent(); + for (int i=0; i<mControllers.size(); i++) { pw.println(); pw.println(mControllers.get(i).getClass().getSimpleName() + ":"); @@ -3109,66 +3187,105 @@ public class JobSchedulerService extends com.android.server.SystemService mControllers.get(i).dumpControllerStateLocked(pw, predicate); pw.decreaseIndent(); } - pw.println(); - pw.println("Uid priority overrides:"); + + boolean overridePrinted = false; for (int i=0; i< mUidPriorityOverride.size(); i++) { int uid = mUidPriorityOverride.keyAt(i); - if (filterUidFinal == -1 || filterUidFinal == UserHandle.getAppId(uid)) { - pw.print(" "); pw.print(UserHandle.formatUid(uid)); + if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) { + if (!overridePrinted) { + overridePrinted = true; + pw.println(); + pw.println("Uid priority overrides:"); + pw.increaseIndent(); + } + pw.print(UserHandle.formatUid(uid)); pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i)); } } - if (mBackingUpUids.size() > 0) { - pw.println(); - pw.println("Backing up uids:"); - boolean first = true; - for (int i = 0; i < mBackingUpUids.size(); i++) { - int uid = mBackingUpUids.keyAt(i); - if (filterUidFinal == -1 || filterUidFinal == UserHandle.getAppId(uid)) { - if (first) { - pw.print(" "); - first = false; - } else { - pw.print(", "); - } - pw.print(UserHandle.formatUid(uid)); + if (overridePrinted) { + pw.decreaseIndent(); + } + + boolean backingPrinted = false; + for (int i = 0; i < mBackingUpUids.size(); i++) { + int uid = mBackingUpUids.keyAt(i); + if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) { + if (!backingPrinted) { + pw.println(); + pw.println("Backing up uids:"); + pw.increaseIndent(); + backingPrinted = true; + } else { + pw.print(", "); } + pw.print(UserHandle.formatUid(uid)); } + } + if (backingPrinted) { + pw.decreaseIndent(); pw.println(); } + pw.println(); - mJobPackageTracker.dump(pw, "", filterUidFinal); + mJobPackageTracker.dump(pw, filterAppId); pw.println(); - if (mJobPackageTracker.dumpHistory(pw, "", filterUidFinal)) { + if (mJobPackageTracker.dumpHistory(pw, filterAppId)) { pw.println(); } + + boolean pendingPrinted = false; pw.println("Pending queue:"); + pw.increaseIndent(); for (int i=0; i<mPendingJobs.size(); i++) { JobStatus job = mPendingJobs.get(i); - pw.print(" Pending #"); pw.print(i); pw.print(": "); + if (!predicate.test(job)) { + continue; + } + if (!pendingPrinted) { + pendingPrinted = true; + } + + pw.print("Pending #"); pw.print(i); pw.print(": "); pw.println(job.toShortString()); - job.dump(pw, " ", false, nowElapsed); + + pw.increaseIndent(); + job.dump(pw, false, nowElapsed); int priority = evaluateJobPriorityLocked(job); - pw.print(" Evaluated priority: "); + pw.print("Evaluated priority: "); pw.println(JobInfo.getPriorityString(priority)); - pw.print(" Tag: "); pw.println(job.getTag()); - pw.print(" Enq: "); + pw.print("Tag: "); pw.println(job.getTag()); + pw.print("Enq: "); TimeUtils.formatDuration(job.madePending - nowUptime, pw); + pw.decreaseIndent(); pw.println(); } + if (!pendingPrinted) { + pw.println("None"); + } + pw.decreaseIndent(); + pw.println(); pw.println("Active jobs:"); pw.increaseIndent(); for (int i=0; i<mActiveServices.size(); i++) { JobServiceContext jsc = mActiveServices.get(i); + final JobStatus job = jsc.getRunningJobLocked(); + + if (job != null && !predicate.test(job)) { + continue; + } + pw.print("Slot #"); pw.print(i); pw.print(": "); jsc.dumpLocked(pw, nowElapsed); - final JobStatus job = jsc.getRunningJobLocked(); if (job != null) { pw.increaseIndent(); - job.dump(pw, " ", false, nowElapsed); + + pw.increaseIndent(); + job.dump(pw, false, nowElapsed); + pw.decreaseIndent(); + pw.print("Evaluated priority: "); pw.println(JobInfo.getPriorityString(job.lastEvaluatedPriority)); @@ -3176,8 +3293,8 @@ public class JobSchedulerService extends com.android.server.SystemService TimeUtils.formatDuration(job.madeActive - nowUptime, pw); pw.print(", pending for "); TimeUtils.formatDuration(job.madeActive - job.madePending, pw); - pw.println(); pw.decreaseIndent(); + pw.println(); } } pw.decreaseIndent(); @@ -3199,13 +3316,13 @@ public class JobSchedulerService extends com.android.server.SystemService void dumpInternalProto(final FileDescriptor fd, int filterUid) { ProtoOutputStream proto = new ProtoOutputStream(fd); - final int filterUidFinal = UserHandle.getAppId(filterUid); + final int filterAppId = UserHandle.getAppId(filterUid); final long now = sSystemClock.millis(); final long nowElapsed = sElapsedRealtimeClock.millis(); final long nowUptime = sUptimeMillisClock.millis(); final Predicate<JobStatus> predicate = (js) -> { - return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal - || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal; + return filterAppId == -1 || UserHandle.getAppId(js.getUid()) == filterAppId + || UserHandle.getAppId(js.getSourceUid()) == filterAppId; }; synchronized (mLock) { @@ -3278,7 +3395,7 @@ public class JobSchedulerService extends com.android.server.SystemService } for (int i=0; i< mUidPriorityOverride.size(); i++) { int uid = mUidPriorityOverride.keyAt(i); - if (filterUidFinal == -1 || filterUidFinal == UserHandle.getAppId(uid)) { + if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) { long pToken = proto.start(JobSchedulerServiceDumpProto.PRIORITY_OVERRIDES); proto.write(JobSchedulerServiceDumpProto.PriorityOverride.UID, uid); proto.write(JobSchedulerServiceDumpProto.PriorityOverride.OVERRIDE_VALUE, @@ -3288,15 +3405,15 @@ public class JobSchedulerService extends com.android.server.SystemService } for (int i = 0; i < mBackingUpUids.size(); i++) { int uid = mBackingUpUids.keyAt(i); - if (filterUidFinal == -1 || filterUidFinal == UserHandle.getAppId(uid)) { + if (filterAppId == -1 || filterAppId == UserHandle.getAppId(uid)) { proto.write(JobSchedulerServiceDumpProto.BACKING_UP_UIDS, uid); } } mJobPackageTracker.dump(proto, JobSchedulerServiceDumpProto.PACKAGE_TRACKER, - filterUidFinal); + filterAppId); mJobPackageTracker.dumpHistory(proto, JobSchedulerServiceDumpProto.HISTORY, - filterUidFinal); + filterAppId); for (JobStatus job : mPendingJobs) { final long pjToken = proto.start(JobSchedulerServiceDumpProto.PENDING_JOBS); 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 0aca2461b41c..be91947b0445 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -17,9 +17,9 @@ package com.android.server.job; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE; -import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.job.IJobCallback; import android.app.job.IJobService; @@ -76,14 +76,6 @@ public final class JobServiceContext implements ServiceConnection { private static final boolean DEBUG_STANDBY = JobSchedulerService.DEBUG_STANDBY; private static final String TAG = "JobServiceContext"; - /** Amount of time a job is allowed to execute for before being considered timed-out. */ - public static final long DEFAULT_EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000; // 10mins. - /** - * Amount of time a RESTRICTED expedited job is allowed to execute for before being considered - * timed-out. - */ - public static final long DEFAULT_RESTRICTED_EXPEDITED_JOB_EXECUTING_TIMESLICE_MILLIS = - DEFAULT_EXECUTING_TIMESLICE_MILLIS / 2; /** Amount of time the JobScheduler waits for the initial service launch+bind. */ private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000; /** Amount of time the JobScheduler will wait for a response from an app for a message. */ @@ -110,6 +102,7 @@ public final class JobServiceContext implements ServiceConnection { /** Make callbacks to {@link JobSchedulerService} to inform on job completion status. */ private final JobCompletedListener mCompletedListener; private final JobConcurrencyManager mJobConcurrencyManager; + private final JobSchedulerService mService; /** Used for service binding, etc. */ private final Context mContext; private final Object mLock; @@ -149,6 +142,13 @@ public final class JobServiceContext implements ServiceConnection { private long mExecutionStartTimeElapsed; /** Track when job will timeout. */ private long mTimeoutElapsed; + /** + * The minimum amount of time the context will allow the job to run before checking whether to + * stop it or not. + */ + private long mMinExecutionGuaranteeMillis; + /** The absolute maximum amount of time the job can run */ + private long mMaxExecutionTimeMillis; // Debugging: reason this job was last stopped. public String mStoppedReason; @@ -190,6 +190,7 @@ public final class JobServiceContext implements ServiceConnection { IBatteryStats batteryStats, JobPackageTracker tracker, Looper looper) { mContext = service.getContext(); mLock = service.getLock(); + mService = service; mBatteryStats = batteryStats; mJobPackageTracker = tracker; mCallbackHandler = new JobServiceHandler(looper); @@ -239,6 +240,9 @@ public final class JobServiceContext implements ServiceConnection { isDeadlineExpired, job.shouldTreatAsExpeditedJob(), triggeredUris, triggeredAuthorities, job.network); mExecutionStartTimeElapsed = sElapsedRealtimeClock.millis(); + mMinExecutionGuaranteeMillis = mService.getMinJobExecutionGuaranteeMs(job); + mMaxExecutionTimeMillis = + Math.max(mService.getMaxJobExecutionTimeMs(job), mMinExecutionGuaranteeMillis); final long whenDeferred = job.getWhenStandbyDeferred(); if (whenDeferred > 0) { @@ -352,8 +356,8 @@ public final class JobServiceContext implements ServiceConnection { } @GuardedBy("mLock") - void preemptExecutingJobLocked() { - doCancelLocked(JobParameters.REASON_PREEMPT, "cancelled due to preemption"); + void preemptExecutingJobLocked(@NonNull String reason) { + doCancelLocked(JobParameters.REASON_PREEMPT, reason); } int getPreferredUid() { @@ -372,6 +376,11 @@ public final class JobServiceContext implements ServiceConnection { return mTimeoutElapsed; } + boolean isWithinExecutionGuaranteeTime() { + return mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis + < sElapsedRealtimeClock.millis(); + } + @GuardedBy("mLock") boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId, String reason) { @@ -607,7 +616,7 @@ public final class JobServiceContext implements ServiceConnection { } @GuardedBy("mLock") - void doCancelLocked(int arg1, String debugReason) { + private void doCancelLocked(int stopReasonCode, String debugReason) { if (mVerb == VERB_FINISHED) { if (DEBUG) { Slog.d(TAG, @@ -615,8 +624,8 @@ public final class JobServiceContext implements ServiceConnection { } return; } - mParams.setStopReason(arg1, debugReason); - if (arg1 == JobParameters.REASON_PREEMPT) { + mParams.setStopReason(stopReasonCode, debugReason); + if (stopReasonCode == JobParameters.REASON_PREEMPT) { mPreferredUid = mRunningJob != null ? mRunningJob.getUid() : NO_PREFERRED_UID; } @@ -767,11 +776,30 @@ public final class JobServiceContext implements ServiceConnection { closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping"); break; case VERB_EXECUTING: - // Not an error - client ran out of time. - Slog.i(TAG, "Client timed out while executing (no jobFinished received), " + - "sending onStop: " + getRunningJobNameLocked()); - mParams.setStopReason(JobParameters.REASON_TIMEOUT, "client timed out"); - sendStopMessageLocked("timeout while executing"); + final long latestStopTimeElapsed = + mExecutionStartTimeElapsed + mMaxExecutionTimeMillis; + final long nowElapsed = sElapsedRealtimeClock.millis(); + if (nowElapsed >= latestStopTimeElapsed) { + // Not an error - client ran out of time. + Slog.i(TAG, "Client timed out while executing (no jobFinished received)." + + " Sending onStop: " + getRunningJobNameLocked()); + mParams.setStopReason(JobParameters.REASON_TIMEOUT, "client timed out"); + sendStopMessageLocked("timeout while executing"); + } else { + // We've given the app the minimum execution time. See if we should stop it or + // let it continue running + final String reason = mJobConcurrencyManager.shouldStopRunningJobLocked(this); + if (reason != null) { + Slog.i(TAG, "Stopping client after min execution time: " + + getRunningJobNameLocked() + " because " + reason); + mParams.setStopReason(JobParameters.REASON_TIMEOUT, reason); + sendStopMessageLocked(reason); + } else { + Slog.i(TAG, "Letting " + getRunningJobNameLocked() + + " continue to run past min execution time"); + scheduleOpTimeOutLocked(); + } + } break; default: Slog.e(TAG, "Handling timeout for an invalid job state: " @@ -878,10 +906,16 @@ public final class JobServiceContext implements ServiceConnection { final long timeoutMillis; switch (mVerb) { case VERB_EXECUTING: - timeoutMillis = mRunningJob.shouldTreatAsExpeditedJob() - && mRunningJob.getStandbyBucket() == RESTRICTED_INDEX - ? DEFAULT_RESTRICTED_EXPEDITED_JOB_EXECUTING_TIMESLICE_MILLIS - : DEFAULT_EXECUTING_TIMESLICE_MILLIS; + final long earliestStopTimeElapsed = + mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis; + final long latestStopTimeElapsed = + mExecutionStartTimeElapsed + mMaxExecutionTimeMillis; + final long nowElapsed = sElapsedRealtimeClock.millis(); + if (nowElapsed < earliestStopTimeElapsed) { + timeoutMillis = earliestStopTimeElapsed - nowElapsed; + } else { + timeoutMillis = latestStopTimeElapsed - nowElapsed; + } break; case VERB_BINDING: @@ -925,6 +959,13 @@ public final class JobServiceContext implements ServiceConnection { pw.print(", timeout at: "); TimeUtils.formatDuration(mTimeoutElapsed - nowElapsed, pw); pw.println(); + pw.print("Remaining execution limits: ["); + TimeUtils.formatDuration( + (mExecutionStartTimeElapsed + mMinExecutionGuaranteeMillis) - nowElapsed, pw); + pw.print(", "); + TimeUtils.formatDuration( + (mExecutionStartTimeElapsed + mMaxExecutionTimeMillis) - nowElapsed, pw); + pw.println("]"); pw.decreaseIndent(); } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index d249f2ae813c..14484ff441ca 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -325,6 +325,8 @@ public final class ConnectivityController extends RestrictingController implemen */ private boolean isInsane(JobStatus jobStatus, Network network, NetworkCapabilities capabilities, Constants constants) { + // Use the maximum possible time since it gives us an upper bound, even though the job + // could end up stopping earlier. final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus); final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes(); 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 539c3c960f2e..6917fb531ac4 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 @@ -35,6 +35,7 @@ import android.os.UserHandle; import android.provider.MediaStore; import android.text.format.DateFormat; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Pair; import android.util.Slog; import android.util.TimeUtils; @@ -1644,14 +1645,18 @@ public final class JobStatus { } } - private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) { - pw.print(prefix); pw.print(" #"); pw.print(index); pw.print(": #"); + private void dumpJobWorkItem(IndentingPrintWriter pw, JobWorkItem work, int index) { + pw.increaseIndent(); + pw.print("#"); pw.print(index); pw.print(": #"); pw.print(work.getWorkId()); pw.print(" "); pw.print(work.getDeliveryCount()); pw.print("x "); pw.println(work.getIntent()); if (work.getGrants() != null) { - pw.print(prefix); pw.println(" URI grants:"); - ((GrantedUriPermissions)work.getGrants()).dump(pw, prefix + " "); + pw.println("URI grants:"); + pw.increaseIndent(); + ((GrantedUriPermissions) work.getGrants()).dump(pw); + pw.decreaseIndent(); } + pw.decreaseIndent(); } private void dumpJobWorkItem(ProtoOutputStream proto, long fieldId, JobWorkItem work) { @@ -1695,36 +1700,38 @@ public final class JobStatus { } // Dumpsys infrastructure - public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) { - pw.print(prefix); UserHandle.formatUid(pw, callingUid); + public void dump(IndentingPrintWriter pw, boolean full, long elapsedRealtimeMillis) { + UserHandle.formatUid(pw, callingUid); pw.print(" tag="); pw.println(tag); - pw.print(prefix); + pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid()); pw.print(" user="); pw.print(getSourceUserId()); pw.print(" pkg="); pw.println(getSourcePackageName()); if (full) { - pw.print(prefix); pw.println("JobInfo:"); - pw.print(prefix); pw.print(" Service: "); + pw.println("JobInfo:"); + pw.increaseIndent(); + + pw.print("Service: "); pw.println(job.getService().flattenToShortString()); if (job.isPeriodic()) { - pw.print(prefix); pw.print(" PERIODIC: interval="); + pw.print("PERIODIC: interval="); TimeUtils.formatDuration(job.getIntervalMillis(), pw); pw.print(" flex="); TimeUtils.formatDuration(job.getFlexMillis(), pw); pw.println(); } if (job.isPersisted()) { - pw.print(prefix); pw.println(" PERSISTED"); + pw.println("PERSISTED"); } if (job.getPriority() != 0) { - pw.print(prefix); pw.print(" Priority: "); + pw.print("Priority: "); pw.println(JobInfo.getPriorityString(job.getPriority())); } if (job.getFlags() != 0) { - pw.print(prefix); pw.print(" Flags: "); + pw.print("Flags: "); pw.println(Integer.toHexString(job.getFlags())); } if (getInternalFlags() != 0) { - pw.print(prefix); pw.print(" Internal flags: "); + pw.print("Internal flags: "); pw.print(Integer.toHexString(getInternalFlags())); if ((getInternalFlags()&INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0) { @@ -1732,106 +1739,109 @@ public final class JobStatus { } pw.println(); } - pw.print(prefix); pw.print(" Requires: charging="); + pw.print("Requires: charging="); pw.print(job.isRequireCharging()); pw.print(" batteryNotLow="); pw.print(job.isRequireBatteryNotLow()); pw.print(" deviceIdle="); pw.println(job.isRequireDeviceIdle()); if (job.getTriggerContentUris() != null) { - pw.print(prefix); pw.println(" Trigger content URIs:"); + pw.println("Trigger content URIs:"); + pw.increaseIndent(); for (int i = 0; i < job.getTriggerContentUris().length; i++) { JobInfo.TriggerContentUri trig = job.getTriggerContentUris()[i]; - pw.print(prefix); pw.print(" "); pw.print(Integer.toHexString(trig.getFlags())); pw.print(' '); pw.println(trig.getUri()); } + pw.decreaseIndent(); if (job.getTriggerContentUpdateDelay() >= 0) { - pw.print(prefix); pw.print(" Trigger update delay: "); + pw.print("Trigger update delay: "); TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw); pw.println(); } if (job.getTriggerContentMaxDelay() >= 0) { - pw.print(prefix); pw.print(" Trigger max delay: "); + pw.print("Trigger max delay: "); TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw); pw.println(); } } if (job.getExtras() != null && !job.getExtras().isDefinitelyEmpty()) { - pw.print(prefix); pw.print(" Extras: "); + pw.print("Extras: "); pw.println(job.getExtras().toShortString()); } if (job.getTransientExtras() != null && !job.getTransientExtras().isDefinitelyEmpty()) { - pw.print(prefix); pw.print(" Transient extras: "); + pw.print("Transient extras: "); pw.println(job.getTransientExtras().toShortString()); } if (job.getClipData() != null) { - pw.print(prefix); pw.print(" Clip data: "); + pw.print("Clip data: "); StringBuilder b = new StringBuilder(128); b.append(job.getClipData()); pw.println(b); } if (uriPerms != null) { - pw.print(prefix); pw.println(" Granted URI permissions:"); - uriPerms.dump(pw, prefix + " "); + pw.println("Granted URI permissions:"); + uriPerms.dump(pw); } if (job.getRequiredNetwork() != null) { - pw.print(prefix); pw.print(" Network type: "); + pw.print("Network type: "); pw.println(job.getRequiredNetwork()); } if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { - pw.print(prefix); pw.print(" Network download bytes: "); + pw.print("Network download bytes: "); pw.println(mTotalNetworkDownloadBytes); } if (mTotalNetworkUploadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) { - pw.print(prefix); pw.print(" Network upload bytes: "); + pw.print("Network upload bytes: "); pw.println(mTotalNetworkUploadBytes); } if (job.getMinLatencyMillis() != 0) { - pw.print(prefix); pw.print(" Minimum latency: "); + pw.print("Minimum latency: "); TimeUtils.formatDuration(job.getMinLatencyMillis(), pw); pw.println(); } if (job.getMaxExecutionDelayMillis() != 0) { - pw.print(prefix); pw.print(" Max execution delay: "); + pw.print("Max execution delay: "); TimeUtils.formatDuration(job.getMaxExecutionDelayMillis(), pw); pw.println(); } - pw.print(prefix); pw.print(" Backoff: policy="); pw.print(job.getBackoffPolicy()); + pw.print("Backoff: policy="); pw.print(job.getBackoffPolicy()); pw.print(" initial="); TimeUtils.formatDuration(job.getInitialBackoffMillis(), pw); pw.println(); if (job.hasEarlyConstraint()) { - pw.print(prefix); pw.println(" Has early constraint"); + pw.println("Has early constraint"); } if (job.hasLateConstraint()) { - pw.print(prefix); pw.println(" Has late constraint"); + pw.println("Has late constraint"); } + + pw.decreaseIndent(); } - pw.print(prefix); pw.print("Required constraints:"); + + pw.print("Required constraints:"); dumpConstraints(pw, requiredConstraints); pw.println(); - pw.print(prefix); pw.print("Dynamic constraints:"); dumpConstraints(pw, mDynamicConstraints); pw.println(); if (full) { - pw.print(prefix); pw.print("Satisfied constraints:"); + pw.print("Satisfied constraints:"); dumpConstraints(pw, satisfiedConstraints); pw.println(); - pw.print(prefix); pw.print("Unsatisfied constraints:"); + pw.print("Unsatisfied constraints:"); dumpConstraints(pw, ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints)); pw.println(); if (dozeWhitelisted) { - pw.print(prefix); pw.println("Doze whitelisted: true"); + pw.println("Doze whitelisted: true"); } if (uidActive) { - pw.print(prefix); pw.println("Uid: active"); + pw.println("Uid: active"); } if (job.isExemptedFromAppStandby()) { - pw.print(prefix); pw.println("Is exempted from app standby"); + pw.println("Is exempted from app standby"); } } if (trackingControllers != 0) { - pw.print(prefix); pw.print("Tracking:"); + pw.print("Tracking:"); if ((trackingControllers&TRACKING_BATTERY) != 0) pw.print(" BATTERY"); if ((trackingControllers&TRACKING_CONNECTIVITY) != 0) pw.print(" CONNECTIVITY"); if ((trackingControllers&TRACKING_CONTENT) != 0) pw.print(" CONTENT"); @@ -1842,76 +1852,78 @@ public final class JobStatus { pw.println(); } - pw.print(prefix); pw.println("Implicit constraints:"); - pw.print(prefix); pw.print(" readyNotDozing: "); + pw.println("Implicit constraints:"); + pw.increaseIndent(); + pw.print("readyNotDozing: "); pw.println(mReadyNotDozing); - pw.print(prefix); pw.print(" readyNotRestrictedInBg: "); + pw.print("readyNotRestrictedInBg: "); pw.println(mReadyNotRestrictedInBg); if (!job.isPeriodic() && hasDeadlineConstraint()) { - pw.print(prefix); pw.print(" readyDeadlineSatisfied: "); + pw.print("readyDeadlineSatisfied: "); pw.println(mReadyDeadlineSatisfied); } if (mDynamicConstraints != 0) { - pw.print(prefix); - pw.print(" readyDynamicSatisfied: "); + pw.print("readyDynamicSatisfied: "); pw.println(mReadyDynamicSatisfied); } - pw.print(prefix); - pw.print(" readyComponentEnabled: "); + pw.print("readyComponentEnabled: "); pw.println(serviceInfo != null); if ((getFlags() & JobInfo.FLAG_EXPEDITED) != 0) { - pw.print(prefix); - pw.print(" mReadyWithinExpeditedQuota: "); + pw.print("readyWithinExpeditedQuota: "); pw.println(mReadyWithinExpeditedQuota); } + pw.decreaseIndent(); if (changedAuthorities != null) { - pw.print(prefix); pw.println("Changed authorities:"); + pw.println("Changed authorities:"); + pw.increaseIndent(); for (int i=0; i<changedAuthorities.size(); i++) { - pw.print(prefix); pw.print(" "); pw.println(changedAuthorities.valueAt(i)); + pw.println(changedAuthorities.valueAt(i)); } + pw.decreaseIndent(); } if (changedUris != null) { - pw.print(prefix); pw.println("Changed URIs:"); + pw.increaseIndent(); for (int i = 0; i < changedUris.size(); i++) { - pw.print(prefix); - pw.print(" "); pw.println(changedUris.valueAt(i)); } + pw.decreaseIndent(); } if (network != null) { - pw.print(prefix); pw.print("Network: "); pw.println(network); + pw.print("Network: "); pw.println(network); } if (pendingWork != null && pendingWork.size() > 0) { - pw.print(prefix); pw.println("Pending work:"); + pw.println("Pending work:"); for (int i = 0; i < pendingWork.size(); i++) { - dumpJobWorkItem(pw, prefix, pendingWork.get(i), i); + dumpJobWorkItem(pw, pendingWork.get(i), i); } } if (executingWork != null && executingWork.size() > 0) { - pw.print(prefix); pw.println("Executing work:"); + pw.println("Executing work:"); for (int i = 0; i < executingWork.size(); i++) { - dumpJobWorkItem(pw, prefix, executingWork.get(i), i); + dumpJobWorkItem(pw, executingWork.get(i), i); } } - pw.print(prefix); pw.print("Standby bucket: "); + pw.print("Standby bucket: "); pw.println(getBucketName()); + pw.increaseIndent(); if (whenStandbyDeferred != 0) { - pw.print(prefix); pw.print(" Deferred since: "); + pw.print("Deferred since: "); TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw); pw.println(); } if (mFirstForceBatchedTimeElapsed != 0) { - pw.print(prefix); - pw.print(" Time since first force batch attempt: "); + pw.print("Time since first force batch attempt: "); TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, elapsedRealtimeMillis, pw); pw.println(); } - pw.print(prefix); pw.print("Enqueue time: "); + pw.decreaseIndent(); + + pw.print("Enqueue time: "); TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw); pw.println(); - pw.print(prefix); pw.print("Run time: earliest="); + pw.print("Run time: earliest="); formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis); pw.print(", latest="); formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis); @@ -1920,14 +1932,14 @@ public final class JobStatus { NO_LATEST_RUNTIME, elapsedRealtimeMillis); pw.println(); if (numFailures != 0) { - pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures); + pw.print("Num failures: "); pw.println(numFailures); } if (mLastSuccessfulRunTime != 0) { - pw.print(prefix); pw.print("Last successful run: "); + pw.print("Last successful run: "); pw.println(formatTime(mLastSuccessfulRunTime)); } if (mLastFailedRunTime != 0) { - pw.print(prefix); pw.print("Last failed run: "); + pw.print("Last failed run: "); pw.println(formatTime(mLastFailedRunTime)); } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index f2d10ac0f7d7..2196b16e0846 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -72,7 +72,6 @@ import com.android.server.LocalServices; import com.android.server.PowerAllowlistInternal; import com.android.server.job.ConstantsProto; import com.android.server.job.JobSchedulerService; -import com.android.server.job.JobServiceContext; import com.android.server.job.StateControllerProto; import com.android.server.usage.AppStandbyInternal; import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener; @@ -770,18 +769,38 @@ public final class QuotaController extends StateController { /** Returns the maximum amount of time this job could run for. */ public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) { - // If quota is currently "free", then the job can run for the full amount of time. - if (mChargeTracker.isCharging() - || isTopStartedJobLocked(jobStatus) - || isUidInForeground(jobStatus.getSourceUid())) { - return JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS; - } - if (jobStatus.shouldTreatAsExpeditedJob()) { - return jobStatus.getStandbyBucket() == RESTRICTED_INDEX - ? JobServiceContext.DEFAULT_RESTRICTED_EXPEDITED_JOB_EXECUTING_TIMESLICE_MILLIS - : JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS; - } - return getRemainingExecutionTimeLocked(jobStatus); + // Need to look at current proc state as well in the case where the job hasn't started yet. + final boolean isTop = mActivityManagerInternal + .getUidProcessState(jobStatus.getSourceUid()) <= ActivityManager.PROCESS_STATE_TOP; + + if (!jobStatus.shouldTreatAsExpeditedJob()) { + // If quota is currently "free", then the job can run for the full amount of time. + if (mChargeTracker.isCharging() + || isTop + || isTopStartedJobLocked(jobStatus) + || isUidInForeground(jobStatus.getSourceUid())) { + return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; + } + return getTimeUntilQuotaConsumedLocked( + jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); + } + + // Expedited job. + if (mChargeTracker.isCharging()) { + return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS; + } + if (isTop || isTopStartedJobLocked(jobStatus)) { + return Math.max(mEJLimitsMs[ACTIVE_INDEX] / 2, + getTimeUntilEJQuotaConsumedLocked( + jobStatus.getSourceUserId(), jobStatus.getSourcePackageName())); + } + if (isUidInForeground(jobStatus.getSourceUid())) { + return Math.max(mEJLimitsMs[WORKING_INDEX] / 2, + getTimeUntilEJQuotaConsumedLocked( + jobStatus.getSourceUserId(), jobStatus.getSourcePackageName())); + } + return getTimeUntilEJQuotaConsumedLocked( + jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); } /** @return true if the job is within expedited job quota. */ @@ -3577,8 +3596,8 @@ public final class QuotaController extends StateController { mEJLimitsMs[RARE_INDEX] = newRareLimitMs; mShouldReevaluateConstraints = true; } - // The limit must be in the range [0 minutes, rare limit]. - long newRestrictedLimitMs = Math.max(0, + // The limit must be in the range [5 minutes, rare limit]. + long newRestrictedLimitMs = Math.max(5 * MINUTE_IN_MILLIS, Math.min(newRareLimitMs, EJ_LIMIT_RESTRICTED_MS)); if (mEJLimitsMs[RESTRICTED_INDEX] != newRestrictedLimitMs) { mEJLimitsMs[RESTRICTED_INDEX] = newRestrictedLimitMs; diff --git a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java index 40c8ce0d5c89..954a5b8bdaa8 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java +++ b/apex/jobscheduler/service/java/com/android/server/job/restrictions/ThermalStatusRestriction.java @@ -64,7 +64,7 @@ public class ThermalStatusRestriction extends JobRestriction { @Override public void dumpConstants(IndentingPrintWriter pw) { pw.print("In thermal throttling?: "); - pw.print(mIsThermalRestricted); + pw.println(mIsThermalRestricted); } @Override diff --git a/core/api/current.txt b/core/api/current.txt index d3d754c0d8a5..742004b24541 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -10444,6 +10444,7 @@ package android.content { field public static final int CONTEXT_RESTRICTED = 4; // 0x4 field public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps"; field public static final String DEVICE_POLICY_SERVICE = "device_policy"; + field public static final String DISPLAY_HASH_SERVICE = "display_hash"; field public static final String DISPLAY_SERVICE = "display"; field public static final String DOWNLOAD_SERVICE = "download"; field public static final String DROPBOX_SERVICE = "dropbox"; @@ -21117,15 +21118,15 @@ package android.media { public static final class MediaCodec.CryptoException extends java.lang.RuntimeException { ctor public MediaCodec.CryptoException(int, @Nullable String); method public int getErrorCode(); - field public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8 - field public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4 - field public static final int ERROR_INSUFFICIENT_SECURITY = 7; // 0x7 - field public static final int ERROR_KEY_EXPIRED = 2; // 0x2 - field public static final int ERROR_LOST_STATE = 9; // 0x9 - field public static final int ERROR_NO_KEY = 1; // 0x1 - field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3 - field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5 - field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6 + field @Deprecated public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8 + field @Deprecated public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4 + field @Deprecated public static final int ERROR_INSUFFICIENT_SECURITY = 7; // 0x7 + field @Deprecated public static final int ERROR_KEY_EXPIRED = 2; // 0x2 + field @Deprecated public static final int ERROR_LOST_STATE = 9; // 0x9 + field @Deprecated public static final int ERROR_NO_KEY = 1; // 0x1 + field @Deprecated public static final int ERROR_RESOURCE_BUSY = 3; // 0x3 + field @Deprecated public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5 + field @Deprecated public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6 } public static final class MediaCodec.CryptoInfo { @@ -21744,6 +21745,42 @@ package android.media { method public boolean verify(@NonNull byte[], @NonNull byte[], @NonNull byte[]); } + public static final class MediaDrm.ErrorCodes { + field public static final int ERROR_CERTIFICATE_MALFORMED = 10; // 0xa + field public static final int ERROR_CERTIFICATE_MISSING = 11; // 0xb + field public static final int ERROR_CRYPTO_LIBRARY = 12; // 0xc + field public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8 + field public static final int ERROR_GENERIC_OEM = 13; // 0xd + field public static final int ERROR_GENERIC_PLUGIN = 14; // 0xe + field public static final int ERROR_INIT_DATA = 15; // 0xf + field public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4 + field public static final int ERROR_INSUFFICIENT_SECURITY = 7; // 0x7 + field public static final int ERROR_KEY_EXPIRED = 2; // 0x2 + field public static final int ERROR_KEY_NOT_LOADED = 16; // 0x10 + field public static final int ERROR_LICENSE_PARSE = 17; // 0x11 + field public static final int ERROR_LICENSE_POLICY = 18; // 0x12 + field public static final int ERROR_LICENSE_RELEASE = 19; // 0x13 + field public static final int ERROR_LICENSE_REQUEST_REJECTED = 20; // 0x14 + field public static final int ERROR_LICENSE_RESTORE = 21; // 0x15 + field public static final int ERROR_LICENSE_STATE = 22; // 0x16 + field public static final int ERROR_LOST_STATE = 9; // 0x9 + field public static final int ERROR_MEDIA_FRAMEWORK = 23; // 0x17 + field public static final int ERROR_NO_KEY = 1; // 0x1 + field public static final int ERROR_PROVISIONING_CERTIFICATE = 24; // 0x18 + field public static final int ERROR_PROVISIONING_CONFIG = 25; // 0x19 + field public static final int ERROR_PROVISIONING_PARSE = 26; // 0x1a + field public static final int ERROR_PROVISIONING_RETRY = 27; // 0x1b + field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3 + field public static final int ERROR_RESOURCE_CONTENTION = 28; // 0x1c + field public static final int ERROR_SECURE_STOP_RELEASE = 29; // 0x1d + field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5 + field public static final int ERROR_STORAGE_READ = 30; // 0x1e + field public static final int ERROR_STORAGE_WRITE = 31; // 0x1f + field public static final int ERROR_UNKNOWN = 0; // 0x0 + field public static final int ERROR_UNSUPPORTED_OPERATION = 6; // 0x6 + field public static final int ERROR_ZERO_SUBSAMPLES = 32; // 0x20 + } + @Deprecated @IntDef({android.media.MediaDrm.HDCP_LEVEL_UNKNOWN, android.media.MediaDrm.HDCP_NONE, android.media.MediaDrm.HDCP_V1, android.media.MediaDrm.HDCP_V2, android.media.MediaDrm.HDCP_V2_1, android.media.MediaDrm.HDCP_V2_2, android.media.MediaDrm.HDCP_V2_3, android.media.MediaDrm.HDCP_NO_DIGITAL_OUTPUT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MediaDrm.HdcpLevel { } @@ -21777,6 +21814,8 @@ package android.media { public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException { method @NonNull public String getDiagnosticInfo(); + method public int getErrorCode(); + method public boolean isTransient(); } public static final class MediaDrm.MetricsConstants { @@ -21843,9 +21882,10 @@ package android.media { public static final class MediaDrm.SessionException extends java.lang.RuntimeException { ctor public MediaDrm.SessionException(int, @Nullable String); - method public int getErrorCode(); - field public static final int ERROR_RESOURCE_CONTENTION = 1; // 0x1 - field public static final int ERROR_UNKNOWN = 0; // 0x0 + method @Deprecated public int getErrorCode(); + method public boolean isTransient(); + field @Deprecated public static final int ERROR_RESOURCE_CONTENTION = 1; // 0x1 + field @Deprecated public static final int ERROR_UNKNOWN = 0; // 0x0 } public class MediaDrmException extends java.lang.Exception { @@ -26985,6 +27025,15 @@ package android.net.vcn { method @NonNull public android.net.vcn.VcnConfig build(); } + public abstract class VcnControlPlaneConfig { + } + + public final class VcnControlPlaneIkeConfig extends android.net.vcn.VcnControlPlaneConfig { + ctor public VcnControlPlaneIkeConfig(@NonNull android.net.ipsec.ike.IkeSessionParams, @NonNull android.net.ipsec.ike.TunnelModeChildSessionParams); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams getChildSessionParams(); + method @NonNull public android.net.ipsec.ike.IkeSessionParams getIkeSessionParams(); + } + public final class VcnGatewayConnectionConfig { method @NonNull public int[] getExposedCapabilities(); method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu(); @@ -26993,7 +27042,7 @@ package android.net.vcn { } public static final class VcnGatewayConnectionConfig.Builder { - ctor public VcnGatewayConnectionConfig.Builder(); + ctor public VcnGatewayConnectionConfig.Builder(@NonNull android.net.vcn.VcnControlPlaneConfig); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addRequiredUnderlyingCapability(int); method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build(); @@ -39026,7 +39075,9 @@ package android.speech { field public static final int ERROR_NO_MATCH = 7; // 0x7 field public static final int ERROR_RECOGNIZER_BUSY = 8; // 0x8 field public static final int ERROR_SERVER = 4; // 0x4 + field public static final int ERROR_SERVER_DISCONNECTED = 11; // 0xb field public static final int ERROR_SPEECH_TIMEOUT = 6; // 0x6 + field public static final int ERROR_TOO_MANY_REQUESTS = 10; // 0xa field public static final String RESULTS_RECOGNITION = "results_recognition"; } @@ -48233,6 +48284,7 @@ package android.view { method public android.view.View focusSearch(int); method public void forceHasOverlappingRendering(boolean); method public void forceLayout(); + method @Nullable public void generateDisplayHash(@NonNull String, @Nullable android.graphics.Rect, @NonNull java.util.concurrent.Executor, @NonNull android.view.displayhash.DisplayHashResultCallback); method public static int generateViewId(); method public CharSequence getAccessibilityClassName(); method public android.view.View.AccessibilityDelegate getAccessibilityDelegate(); @@ -51188,6 +51240,41 @@ package android.view.contentcapture { } +package android.view.displayhash { + + public final class DisplayHash implements android.os.Parcelable { + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.displayhash.DisplayHash> CREATOR; + } + + public final class DisplayHashManager { + method @NonNull public java.util.Set<java.lang.String> getSupportedHashAlgorithms(); + method @Nullable public android.view.displayhash.VerifiedDisplayHash verifyDisplayHash(@NonNull android.view.displayhash.DisplayHash); + } + + public interface DisplayHashResultCallback { + method public void onDisplayHashError(int); + method public void onDisplayHashResult(@NonNull android.view.displayhash.DisplayHash); + field public static final int DISPLAY_HASH_ERROR_INVALID_BOUNDS = -2; // 0xfffffffe + field public static final int DISPLAY_HASH_ERROR_MISSING_WINDOW = -3; // 0xfffffffd + field public static final int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4; // 0xfffffffc + field public static final int DISPLAY_HASH_ERROR_UNKNOWN = -1; // 0xffffffff + } + + public final class VerifiedDisplayHash implements android.os.Parcelable { + ctor public VerifiedDisplayHash(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[]); + method public int describeContents(); + method @NonNull public android.graphics.Rect getBoundsInWindow(); + method @NonNull public String getHashAlgorithm(); + method @NonNull public byte[] getImageHash(); + method public long getTimeMillis(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.displayhash.VerifiedDisplayHash> CREATOR; + } + +} + package android.view.inputmethod { public class BaseInputConnection implements android.view.inputmethod.InputConnection { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index deff7b38ea2a..7e83426dc7cd 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -9984,6 +9984,18 @@ package android.service.dataloader { } +package android.service.displayhash { + + public abstract class DisplayHasherService extends android.app.Service { + ctor public DisplayHasherService(); + method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); + method @Nullable public abstract void onGenerateDisplayHash(@NonNull byte[], @NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String, @NonNull android.view.displayhash.DisplayHashResultCallback); + method @Nullable public abstract android.view.displayhash.VerifiedDisplayHash onVerifyDisplayHash(@NonNull byte[], @NonNull android.view.displayhash.DisplayHash); + field public static final String SERVICE_INTERFACE = "android.service.displayhash.DisplayHasherService"; + } + +} + package android.service.euicc { public final class DownloadSubscriptionResult implements android.os.Parcelable { @@ -10344,30 +10356,6 @@ package android.service.rotationresolver { } -package android.service.screenshot { - - public final class ScreenshotHash implements android.os.Parcelable { - ctor public ScreenshotHash(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]); - method public int describeContents(); - method @NonNull public android.graphics.Rect getBoundsInWindow(); - method @NonNull public String getHashingAlgorithm(); - method @NonNull public byte[] getHmac(); - method @NonNull public byte[] getImageHash(); - method public long getScreenshotTimeMillis(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.service.screenshot.ScreenshotHash> CREATOR; - } - - public abstract class ScreenshotHasherService extends android.app.Service { - ctor public ScreenshotHasherService(); - method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); - method @Nullable public abstract android.service.screenshot.ScreenshotHash onGenerateScreenshotHash(@NonNull byte[], @NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String); - method public abstract boolean onVerifyScreenshotHash(@NonNull byte[], @NonNull android.service.screenshot.ScreenshotHash); - field public static final String SERVICE_INTERFACE = "android.service.screenshot.ScreenshotHasherService"; - } - -} - package android.service.search { public abstract class SearchUiService extends android.app.Service { @@ -14399,6 +14387,21 @@ package android.view.contentcapture { } +package android.view.displayhash { + + public final class DisplayHash implements android.os.Parcelable { + ctor public DisplayHash(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]); + method public int describeContents(); + method @NonNull public android.graphics.Rect getBoundsInWindow(); + method @NonNull public String getHashAlgorithm(); + method @NonNull public byte[] getHmac(); + method @NonNull public byte[] getImageHash(); + method public long getTimeMillis(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + } + +} + package android.view.translation { public final class UiTranslationManager { diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index a9e28bb635be..b1c39d39d414 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -209,4 +209,10 @@ oneway interface ITaskStackListener { * @param taskInfo info about the task which moved */ void onTaskMovedToBack(in ActivityManager.RunningTaskInfo taskInfo); + + /** + * Called when the lock task mode changes. See ActivityManager#LOCK_TASK_MODE_* and + * LockTaskController. + */ + void onLockTaskModeChanged(int mode); } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index c47b546653b9..ffaaa578cdd2 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -211,6 +211,7 @@ import android.view.autofill.AutofillManager; import android.view.autofill.IAutoFillManager; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.IContentCaptureManager; +import android.view.displayhash.DisplayHashManager; import android.view.inputmethod.InputMethodManager; import android.view.textclassifier.TextClassificationManager; import android.view.textservice.TextServicesManager; @@ -1426,6 +1427,13 @@ public final class SystemServiceRegistry { } }); + registerService(Context.DISPLAY_HASH_SERVICE, DisplayHashManager.class, + new CachedServiceFetcher<DisplayHashManager>() { + @Override + public DisplayHashManager createService(ContextImpl ctx) { + return new DisplayHashManager(); + }}); + sInitializing = true; try { // Note: the following functions need to be @SystemApis, once they become mainline diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index 517ae24b75a6..1e382307a1a3 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -193,4 +193,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { @Override public void onTaskMovedToBack(RunningTaskInfo taskInfo) { } + + @Override + public void onLockTaskModeChanged(int mode) { + } } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 51669432e377..0093b6342da6 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5491,6 +5491,14 @@ public abstract class Context { public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification"; /** + * Use with {@link #getSystemService(String)} to access + * {@link android.view.displayhash.DisplayHashManager} to handle display hashes. + * + * @see #getSystemService(String) + */ + public static final String DISPLAY_HASH_SERVICE = "display_hash"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/net/vcn/VcnControlPlaneConfig.java b/core/java/android/net/vcn/VcnControlPlaneConfig.java index 0c6ccfee5d5d..92f6c4440377 100644 --- a/core/java/android/net/vcn/VcnControlPlaneConfig.java +++ b/core/java/android/net/vcn/VcnControlPlaneConfig.java @@ -35,8 +35,6 @@ import java.util.Objects; * * @see VcnManager * @see VcnGatewayConnectionConfig - * - * @hide */ public abstract class VcnControlPlaneConfig { /** @hide */ diff --git a/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java b/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java index 2f6e1f63b960..de086f63b14d 100644 --- a/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java +++ b/core/java/android/net/vcn/VcnControlPlaneIkeConfig.java @@ -34,8 +34,6 @@ import java.util.Objects; * configuration, authentication and authorization parameters. * * @see VcnControlPlaneConfig - * - * @hide */ public final class VcnControlPlaneIkeConfig extends VcnControlPlaneConfig { private static final String TAG = VcnControlPlaneIkeConfig.class.getSimpleName(); diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index 94dff9159bd9..9f83b21f0d0c 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -420,7 +420,6 @@ public final class VcnGatewayConnectionConfig { * * @param ctrlPlaneConfig the control plane configuration * @see VcnControlPlaneConfig - * @hide */ public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) { Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null"); @@ -428,13 +427,6 @@ public final class VcnGatewayConnectionConfig { mCtrlPlaneConfig = ctrlPlaneConfig; } - /** Construct a Builder object. */ - // TODO: Remove this constructor when #Builder(ctrlPlaneConfig) is exposed as public API. - // This constructor is created to avoid changing API shape in this CL - public Builder() { - mCtrlPlaneConfig = null; - } - /** * Add a capability that this VCN Gateway Connection will support. * diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 9c9e4995d673..c8cbc517b226 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -168,8 +168,10 @@ public final class Trace { } /** - * Set whether application tracing is allowed for this process. This is intended to be set - * once at application start-up time based on whether the application is debuggable. + * From Android S, this is no-op. + * + * Before, set whether application tracing is allowed for this process. This is intended to be + * set once at application start-up time based on whether the application is debuggable. * * @hide */ diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java index f2fe71913bb1..a078e0434867 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -36,6 +36,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.DataLoaderParams; import android.content.pm.IDataLoaderStatusListener; +import android.content.pm.IPackageLoadingProgressCallback; import android.content.pm.InstallationFileParcel; import java.io.File; @@ -71,7 +72,8 @@ public final class IncrementalFileStorages { @Nullable StorageHealthCheckParams healthCheckParams, @Nullable IStorageHealthListener healthListener, @NonNull List<InstallationFileParcel> addedFiles, - @NonNull PerUidReadTimeouts[] perUidReadTimeouts) throws IOException { + @NonNull PerUidReadTimeouts[] perUidReadTimeouts, + IPackageLoadingProgressCallback progressCallback) throws IOException { // TODO(b/136132412): validity check if session should not be incremental IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService( Context.INCREMENTAL_SERVICE); @@ -95,6 +97,11 @@ public final class IncrementalFileStorages { throw new IOException("Unknown file location: " + file.location); } } + // Register progress loading callback after files have been added + if (progressCallback != null) { + incrementalManager.registerLoadingProgressCallback(stageDir.getAbsolutePath(), + progressCallback); + } result.startLoading(dataLoaderParams, statusListener, healthCheckParams, healthListener, perUidReadTimeouts); @@ -205,6 +212,7 @@ public final class IncrementalFileStorages { try { mDefaultStorage.unBind(mStageDir.getAbsolutePath()); + mDefaultStorage.unregisterLoadingProgressListener(); } catch (IOException ignored) { } mDefaultStorage = null; diff --git a/core/java/android/service/displayhash/DisplayHasherService.java b/core/java/android/service/displayhash/DisplayHasherService.java new file mode 100644 index 000000000000..331dbe91f6c7 --- /dev/null +++ b/core/java/android/service/displayhash/DisplayHasherService.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.displayhash; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.graphics.Rect; +import android.hardware.HardwareBuffer; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteCallback; +import android.view.displayhash.DisplayHash; +import android.view.displayhash.DisplayHashResultCallback; +import android.view.displayhash.VerifiedDisplayHash; + +/** + * A service that handles generating and verify {@link DisplayHash}. + * + * The service will generate a DisplayHash based on arguments passed in. Then later that + * same DisplayHash can be verified to determine that it was created by the system. + * + * @hide + */ +@SystemApi +public abstract class DisplayHasherService extends Service { + + /** @hide **/ + public static final String EXTRA_VERIFIED_DISPLAY_HASH = + "android.service.displayhash.extra.VERIFIED_DISPLAY_HASH"; + + /** + * Manifest metadata key for the resource string array containing the names of all hashing + * algorithms provided by the service. + * + * @hide + */ + public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = + "android.displayhash.available_algorithms"; + + /** + * The {@link Intent} action that must be declared as handled by a service in its manifest + * for the system to recognize it as a DisplayHash providing service. + * + * @hide + */ + @SystemApi + public static final String SERVICE_INTERFACE = + "android.service.displayhash.DisplayHasherService"; + + private DisplayHasherServiceWrapper mWrapper; + private Handler mHandler; + + public DisplayHasherService() { + } + + @Override + public void onCreate() { + super.onCreate(); + mWrapper = new DisplayHasherServiceWrapper(); + mHandler = new Handler(Looper.getMainLooper(), null, true); + } + + @NonNull + @Override + public final IBinder onBind(@NonNull Intent intent) { + return mWrapper; + } + + /** + * Generates the DisplayHash that can be used to validate that the system generated the + * token. + * + * @param salt The salt to use when generating the hmac. This should be unique to the + * caller so the token cannot be verified by any other process. + * @param buffer The buffer for the content to generate the hash for. + * @param bounds The size and position of the content in window space. + * @param hashAlgorithm The String for the hashing algorithm to use based values in + * {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS)}. + * @param callback The callback to invoke + * {@link DisplayHashResultCallback#onDisplayHashResult(DisplayHash)} + * if successfully generated a DisplayHash or {@link + * DisplayHashResultCallback#onDisplayHashError(int)} if failed. + */ + @Nullable + public abstract void onGenerateDisplayHash(@NonNull byte[] salt, + @NonNull HardwareBuffer buffer, @NonNull Rect bounds, + @NonNull String hashAlgorithm, @NonNull DisplayHashResultCallback callback); + + /** + * Call to verify that the DisplayHash passed in was generated by the system. + * + * @param salt The salt value to use when verifying the hmac. This should be the + * same value that was passed to + * {@link #onGenerateDisplayHash(byte[], + * HardwareBuffer, Rect, String, DisplayHashResultCallback)} to + * generate the token. + * @param displayHash The token to verify that it was generated by the system. + * @return a {@link VerifiedDisplayHash} if the token was generated by the system or null + * if the token cannot be verified. + */ + @Nullable + public abstract VerifiedDisplayHash onVerifyDisplayHash(@NonNull byte[] salt, + @NonNull DisplayHash displayHash); + + private void verifyDisplayHash(byte[] salt, DisplayHash displayHash, + RemoteCallback callback) { + VerifiedDisplayHash verifiedDisplayHash = onVerifyDisplayHash(salt, + displayHash); + final Bundle data = new Bundle(); + data.putParcelable(EXTRA_VERIFIED_DISPLAY_HASH, verifiedDisplayHash); + callback.sendResult(data); + } + + private final class DisplayHasherServiceWrapper extends IDisplayHasherService.Stub { + @Override + public void generateDisplayHash(byte[] salt, HardwareBuffer buffer, Rect bounds, + String hashAlgorithm, RemoteCallback callback) { + mHandler.sendMessage( + obtainMessage(DisplayHasherService::onGenerateDisplayHash, + DisplayHasherService.this, salt, buffer, bounds, + hashAlgorithm, new DisplayHashResultCallback() { + @Override + public void onDisplayHashResult( + @NonNull DisplayHash displayHash) { + Bundle result = new Bundle(); + result.putParcelable(EXTRA_DISPLAY_HASH, displayHash); + callback.sendResult(result); + } + + @Override + public void onDisplayHashError(int errorCode) { + Bundle result = new Bundle(); + result.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode); + callback.sendResult(result); + } + })); + } + + @Override + public void verifyDisplayHash(byte[] salt, DisplayHash displayHash, + RemoteCallback callback) { + mHandler.sendMessage( + obtainMessage(DisplayHasherService::verifyDisplayHash, + DisplayHasherService.this, salt, displayHash, callback)); + } + } +} diff --git a/core/java/android/service/screenshot/IScreenshotHasherService.aidl b/core/java/android/service/displayhash/IDisplayHasherService.aidl index d14d147e096c..236bc28c74c8 100644 --- a/core/java/android/service/screenshot/IScreenshotHasherService.aidl +++ b/core/java/android/service/displayhash/IDisplayHasherService.aidl @@ -14,43 +14,41 @@ * limitations under the License. */ -package android.service.screenshot; +package android.service.displayhash; import android.graphics.Rect; import android.hardware.HardwareBuffer; import android.os.RemoteCallback; -import android.service.screenshot.ScreenshotHash; +import android.view.displayhash.DisplayHash; /** - * Service used to handle ScreenshotHash requests. + * Service used to handle DisplayHash requests. * * @hide */ -oneway interface IScreenshotHasherService { +oneway interface IDisplayHasherService { /** - * Generates the ScreenshotHash token that can be used to validate that the system generated the - * token. + * Generates the DisplayHash that can be used to validate that the system generated the token. * * @param salt The salt to use when generating the hmac. This should be unique to the caller so * the token cannot be verified by any other process. - * @param screenshot The screenshot to generate the hash and add to the token. - * @param bounds The size and position of the content being screenshot in the window. - * @param hashAlgorithm The String for the hashing algorithm to use based on values in + * @param buffer The buffer to generate the hash for. + * @param bounds The size and position of the content being hashed in window space. + * @param hashAlgorithm The String for the hash algorithm to use based on values in * {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS}. - * @param Callback The callback invoked to send back the ScreenshotHash token. + * @param Callback The callback invoked to send back the DisplayHash. */ - void generateScreenshotHash(in byte[] salt, in HardwareBuffer screenshot, in Rect bounds, + void generateDisplayHash(in byte[] salt, in HardwareBuffer buffer, in Rect bounds, in String hashAlgorithm, in RemoteCallback callback); /** - * Call to verify that the ScreenshotHash passed in was generated by the system. The result - * will be sent in the callback as a boolean with the key {@link #EXTRA_VERIFICATION_STATUS}. + * Call to verify that the DisplayHash passed in was generated by the system. The result + * will be sent in the callback as a boolean with the key {@link #EXTRA_VERIFIED_DISPLAY_HASH}. * * @param salt The salt value to use when verifying the hmac. This should be the same value that - * was passed to {@link generateScreenshotHash()} to generate the token. - * @param screenshotHash The hash to verify that it was generated by the system. - * @param callback The callback invoked to send back the verification status. + * was passed to {@link generateDisplayHash()} to generate the DisplayHash. + * @param displayHash The hash to verify that it was generated by the system. + * @param callback The callback invoked to send back the VerifiedDisplayHash. */ - void verifyScreenshotHash(in byte[] salt, in ScreenshotHash screenshotHash, - in RemoteCallback callback); + void verifyDisplayHash(in byte[] salt, in DisplayHash displayHash, in RemoteCallback callback); } diff --git a/core/java/android/service/screenshot/OWNERS b/core/java/android/service/displayhash/OWNERS index 0862c05e0ee4..0862c05e0ee4 100644 --- a/core/java/android/service/screenshot/OWNERS +++ b/core/java/android/service/displayhash/OWNERS diff --git a/core/java/android/service/screenshot/ScreenshotHash.java b/core/java/android/service/screenshot/ScreenshotHash.java deleted file mode 100644 index 9ae4192bb676..000000000000 --- a/core/java/android/service/screenshot/ScreenshotHash.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.service.screenshot; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.graphics.Rect; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.util.DataClass; - -/** - * The screenshot hash used to validate information about what was present on screen. - * @hide - * - * TODO: Remove hide and SystemAPI since this will be a public class - */ -@SystemApi -@DataClass(genToString = true, genAidl = true) -public final class ScreenshotHash implements Parcelable { - /** - * The timestamp when the screenshot was generated. - */ - private final long mScreenshotTimeMillis; - - /** - * The bounds of the requested area to take the screenshot. This is in window space passed in - * by the client. - */ - @NonNull - private final Rect mBoundsInWindow; - - /** - * The selected hashing algorithm that generated the image hash. - */ - @NonNull - private final String mHashingAlgorithm; - - /** - * The image hash generated when creating the ScreenshotHash from the screenshot taken. - */ - @NonNull - private final byte[] mImageHash; - - /** - * The hmac generated by the system and used to verify whether this token was generated by - * the system. This should only be accessed by a system process. - */ - @NonNull - private final byte[] mHmac; - - /** - * The hmac generated by the system and used to verify whether this token was generated by - * the system. This should only be accessed by a system process. - * - * @hide - */ - @SystemApi - @NonNull - public byte[] getHmac() { - return mHmac; - } - - - - // Code below generated by codegen v1.0.22. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/screenshot - // /ScreenshotHash.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - /** - * Creates a new ScreenshotHash. - * - * @param screenshotTimeMillis - * The timestamp when the screenshot was generated. - * @param boundsInWindow - * The bounds of the requested area to take the screenshot. This is in window space passed in - * by the client. - * @param hashingAlgorithm - * The selected hashing algorithm that generated the image hash. - * @param imageHash - * The image hash generated when creating the ScreenshotHash from the screenshot taken. - * @param hmac - * The hmac generated by the system and used to verify whether this token was generated by - * the system. This should only be accessed by a system process. - */ - @DataClass.Generated.Member - public ScreenshotHash( - long screenshotTimeMillis, - @NonNull Rect boundsInWindow, - @NonNull String hashingAlgorithm, - @NonNull byte[] imageHash, - @NonNull byte[] hmac) { - this.mScreenshotTimeMillis = screenshotTimeMillis; - this.mBoundsInWindow = boundsInWindow; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mBoundsInWindow); - this.mHashingAlgorithm = hashingAlgorithm; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mHashingAlgorithm); - this.mImageHash = imageHash; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mImageHash); - this.mHmac = hmac; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mHmac); - - // onConstructed(); // You can define this method to get a callback - } - - /** - * The timestamp when the screenshot was generated. - */ - @DataClass.Generated.Member - public long getScreenshotTimeMillis() { - return mScreenshotTimeMillis; - } - - /** - * The bounds of the requested area to take the screenshot. This is in window space passed in - * by the client. - */ - @DataClass.Generated.Member - public @NonNull Rect getBoundsInWindow() { - return mBoundsInWindow; - } - - /** - * The selected hashing algorithm that generated the image hash. - */ - @DataClass.Generated.Member - public @NonNull String getHashingAlgorithm() { - return mHashingAlgorithm; - } - - /** - * The image hash generated when creating the ScreenshotHash from the screenshot taken. - */ - @DataClass.Generated.Member - public @NonNull byte[] getImageHash() { - return mImageHash; - } - - @Override - @DataClass.Generated.Member - public String toString() { - // You can override field toString logic by defining methods like: - // String fieldNameToString() { ... } - - return "ScreenshotHash { " + - "screenshotTimeMillis = " + mScreenshotTimeMillis + ", " + - "boundsInWindow = " + mBoundsInWindow + ", " + - "hashingAlgorithm = " + mHashingAlgorithm + ", " + - "imageHash = " + java.util.Arrays.toString(mImageHash) + ", " + - "hmac = " + java.util.Arrays.toString(mHmac) + - " }"; - } - - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - dest.writeLong(mScreenshotTimeMillis); - dest.writeTypedObject(mBoundsInWindow, flags); - dest.writeString(mHashingAlgorithm); - dest.writeByteArray(mImageHash); - dest.writeByteArray(mHmac); - } - - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - /* package-private */ ScreenshotHash(@NonNull Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - long screenshotTimeMillis = in.readLong(); - Rect boundsInWindow = (Rect) in.readTypedObject(Rect.CREATOR); - String hashingAlgorithm = in.readString(); - byte[] imageHash = in.createByteArray(); - byte[] hmac = in.createByteArray(); - - this.mScreenshotTimeMillis = screenshotTimeMillis; - this.mBoundsInWindow = boundsInWindow; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mBoundsInWindow); - this.mHashingAlgorithm = hashingAlgorithm; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mHashingAlgorithm); - this.mImageHash = imageHash; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mImageHash); - this.mHmac = hmac; - com.android.internal.util.AnnotationValidations.validate( - NonNull.class, null, mHmac); - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator<ScreenshotHash> CREATOR - = new Parcelable.Creator<ScreenshotHash>() { - @Override - public ScreenshotHash[] newArray(int size) { - return new ScreenshotHash[size]; - } - - @Override - public ScreenshotHash createFromParcel(@NonNull Parcel in) { - return new ScreenshotHash(in); - } - }; - - @DataClass.Generated( - time = 1612383172822L, - codegenVersion = "1.0.22", - sourceFile = "frameworks/base/core/java/android/service/screenshot/ScreenshotHash.java", - inputSignatures = "private final long mScreenshotTimeMillis\nprivate final @android.annotation.NonNull android.graphics.Rect mBoundsInWindow\nprivate final @android.annotation.NonNull java.lang.String mHashingAlgorithm\nprivate final @android.annotation.NonNull byte[] mImageHash\nprivate final @android.annotation.NonNull byte[] mHmac\npublic @android.annotation.SystemApi @android.annotation.NonNull byte[] getHmac()\nclass ScreenshotHash extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genAidl=true)") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - -} diff --git a/core/java/android/service/screenshot/ScreenshotHasherService.java b/core/java/android/service/screenshot/ScreenshotHasherService.java deleted file mode 100644 index d96cc7eaba7a..000000000000 --- a/core/java/android/service/screenshot/ScreenshotHasherService.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.service.screenshot; - -import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.app.Service; -import android.content.Intent; -import android.graphics.Rect; -import android.hardware.HardwareBuffer; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.RemoteCallback; - -/** - * A service that handles generating and verify {@link ScreenshotHash}. - * - * The service will generate a ScreenshotHash based on arguments passed in. Then later that - * same ScreenshotHash can be verified to determine that it was created by the system. - * - * @hide - */ -@SystemApi -public abstract class ScreenshotHasherService extends Service { - /** @hide **/ - public static final String EXTRA_SCREENSHOT_HASH = - "android.service.screenshot.extra.SCREENSHOT_HASH"; - - /** @hide **/ - public static final String EXTRA_VERIFICATION_STATUS = - "android.service.screenshot.extra.VERIFICATION_STATUS"; - - /** - * Manifest metadata key for the resource string array containing the names of all hashing - * algorithms provided by the service. - * - * @hide - */ - public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = - "android.screenshot.available_algorithms"; - - /** - * The {@link Intent} action that must be declared as handled by a service in its manifest - * for the system to recognize it as a ScreenshotHash providing service. - * - * @hide - */ - @SystemApi - public static final String SERVICE_INTERFACE = - "android.service.screenshot.ScreenshotHasherService"; - - private ScreenshotHasherServiceWrapper mWrapper; - private Handler mHandler; - - public ScreenshotHasherService() { - } - - @Override - public void onCreate() { - super.onCreate(); - mWrapper = new ScreenshotHasherServiceWrapper(); - mHandler = new Handler(Looper.getMainLooper(), null, true); - } - - @NonNull - @Override - public final IBinder onBind(@NonNull Intent intent) { - return mWrapper; - } - - /** - * Generates the ScreenshotHash that can be used to validate that the system generated the - * token. - * - * @param salt The salt to use when generating the hmac. This should be unique to the - * caller so the token cannot be verified by any other process. - * @param screenshot The screenshot buffer for the content. - * @param bounds The size and position of the content being screenshot in the window. - * @param hashAlgorithm The String for the hashing algorithm to use based values in - * {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS)}. - * @return A ScreenshotHash that can be used to validate information about the content. - * Returns null when the arguments sent are invalid. - */ - @Nullable - public abstract ScreenshotHash onGenerateScreenshotHash(@NonNull byte[] salt, - @NonNull HardwareBuffer screenshot, @NonNull Rect bounds, - @NonNull String hashAlgorithm); - - /** - * Call to verify that the ScreenshotHash passed in was generated by the system. - * - * @param salt The salt value to use when verifying the hmac. This should be the - * same value that was passed to - * {@link #onGenerateScreenshotHash(byte[], - * HardwareBuffer, Rect, String)} to - * generate the token. - * @param screenshotHash The token to verify that it was generated by the system. - * @return true if the token can be verified that it was generated by the system. - */ - public abstract boolean onVerifyScreenshotHash(@NonNull byte[] salt, - @NonNull ScreenshotHash screenshotHash); - - private void generateScreenshotHash(byte[] salt, HardwareBuffer screenshot, Rect bounds, - String hashAlgorithm, RemoteCallback callback) { - ScreenshotHash screenshotHash = onGenerateScreenshotHash(salt, screenshot, - bounds, - hashAlgorithm); - final Bundle data = new Bundle(); - data.putParcelable(EXTRA_SCREENSHOT_HASH, screenshotHash); - callback.sendResult(data); - } - - private void verifyScreenshotHash(byte[] salt, ScreenshotHash screenshotHash, - RemoteCallback callback) { - boolean verificationStatus = onVerifyScreenshotHash(salt, screenshotHash); - final Bundle data = new Bundle(); - data.putBoolean(EXTRA_VERIFICATION_STATUS, verificationStatus); - callback.sendResult(data); - } - - private final class ScreenshotHasherServiceWrapper extends - IScreenshotHasherService.Stub { - @Override - public void generateScreenshotHash(byte[] salt, HardwareBuffer screenshot, Rect bounds, - String hashAlgorithm, RemoteCallback callback) { - mHandler.sendMessage( - obtainMessage(ScreenshotHasherService::generateScreenshotHash, - ScreenshotHasherService.this, salt, screenshot, bounds, - hashAlgorithm, callback)); - } - - @Override - public void verifyScreenshotHash(byte[] salt, ScreenshotHash screenshotHash, - RemoteCallback callback) { - mHandler.sendMessage( - obtainMessage(ScreenshotHasherService::verifyScreenshotHash, - ScreenshotHasherService.this, salt, screenshotHash, - callback)); - } - } -} diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl index f91e122ea9cb..cc1cdedd0f96 100644 --- a/core/java/android/speech/IRecognitionService.aidl +++ b/core/java/android/speech/IRecognitionService.aidl @@ -43,7 +43,7 @@ oneway interface IRecognitionService { * @param featureId The feature in the package */ void startListening(in Intent recognizerIntent, in IRecognitionListener listener, - String packageName, String featureId); + String packageName, String featureId, int callingUid); /** * Stops listening for speech. Speech captured so far will be recognized as @@ -62,6 +62,7 @@ oneway interface IRecognitionService { * @param listener to receive callbacks, note that this must be non-null * @param packageName the package name calling this API * @param featureId The feature in the package + * @param isShutdown Whether the cancellation is caused by a client calling #shutdown */ - void cancel(in IRecognitionListener listener, String packageName, String featureId); + void cancel(in IRecognitionListener listener, String packageName, String featureId, boolean isShutdown); } diff --git a/core/java/android/speech/IRecognitionServiceManager.aidl b/core/java/android/speech/IRecognitionServiceManager.aidl index 7158ba2f9f63..8e5292d1ddf1 100644 --- a/core/java/android/speech/IRecognitionServiceManager.aidl +++ b/core/java/android/speech/IRecognitionServiceManager.aidl @@ -16,6 +16,8 @@ package android.speech; +import android.content.ComponentName; + import android.speech.IRecognitionServiceManagerCallback; /** @@ -23,6 +25,10 @@ import android.speech.IRecognitionServiceManagerCallback; * * {@hide} */ -interface IRecognitionServiceManager { - void createSession(in IRecognitionServiceManagerCallback callback); +oneway interface IRecognitionServiceManager { + void createSession( + in ComponentName componentName, + in IBinder clientToken, + boolean onDevice, + in IRecognitionServiceManagerCallback callback); } diff --git a/core/java/android/speech/IRecognitionServiceManagerCallback.aidl b/core/java/android/speech/IRecognitionServiceManagerCallback.aidl index d760810deda8..26afdaafd919 100644 --- a/core/java/android/speech/IRecognitionServiceManagerCallback.aidl +++ b/core/java/android/speech/IRecognitionServiceManagerCallback.aidl @@ -25,5 +25,5 @@ import android.speech.IRecognitionService; */ oneway interface IRecognitionServiceManagerCallback { void onSuccess(in IRecognitionService service); - void onError(); + void onError(int errorCode); } diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index c97dbfe38ead..fd584f191743 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -105,17 +105,6 @@ public abstract class RecognitionService extends Service { int callingUid) { if (mCurrentCallback == null) { if (DBG) Log.d(TAG, "created new mCurrentCallback, listener = " + listener.asBinder()); - try { - listener.asBinder().linkToDeath(new IBinder.DeathRecipient() { - @Override - public void binderDied() { - mHandler.sendMessage(mHandler.obtainMessage(MSG_CANCEL, listener)); - } - }, 0); - } catch (RemoteException re) { - Log.e(TAG, "dead listener on startListening"); - return; - } mCurrentCallback = new Callback(listener, callingUid); RecognitionService.this.onStartListening(intent, mCurrentCallback); } else { @@ -352,7 +341,6 @@ public abstract class RecognitionService extends Service { * Return the Linux uid assigned to the process that sent you the current transaction that * is being processed. This is obtained from {@link Binder#getCallingUid()}. */ - // TODO(b/176578753): need to make sure this is fixed when proxied through system. public int getCallingUid() { return mCallingUid; } @@ -368,7 +356,7 @@ public abstract class RecognitionService extends Service { @Override public void startListening(Intent recognizerIntent, IRecognitionListener listener, - String packageName, String featureId) { + String packageName, String featureId, int callingUid) { Preconditions.checkNotNull(packageName); if (DBG) Log.d(TAG, "startListening called by:" + listener.asBinder()); @@ -377,7 +365,7 @@ public abstract class RecognitionService extends Service { packageName, featureId)) { service.mHandler.sendMessage(Message.obtain(service.mHandler, MSG_START_LISTENING, service.new StartListeningArgs( - recognizerIntent, listener, Binder.getCallingUid()))); + recognizerIntent, listener, callingUid))); } } @@ -397,7 +385,7 @@ public abstract class RecognitionService extends Service { @Override public void cancel(IRecognitionListener listener, String packageName, - String featureId) { + String featureId, boolean isShutdown) { Preconditions.checkNotNull(packageName); if (DBG) Log.d(TAG, "cancel called by:" + listener.asBinder()); diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java index de879c63a1a6..850f997a2d2f 100644 --- a/core/java/android/speech/SpeechRecognizer.java +++ b/core/java/android/speech/SpeechRecognizer.java @@ -20,8 +20,8 @@ import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.content.pm.ResolveInfo; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -32,10 +32,9 @@ import android.os.ServiceManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import android.util.Slog; -import java.util.LinkedList; import java.util.List; -import java.util.Queue; /** * This class provides access to the speech recognition service. This service allows access to the @@ -107,6 +106,12 @@ public class SpeechRecognizer { /** Insufficient permissions */ public static final int ERROR_INSUFFICIENT_PERMISSIONS = 9; + /** Too many requests from the same client. */ + public static final int ERROR_TOO_MANY_REQUESTS = 10; + + /** Server has been disconnected, e.g. because the app has crashed. */ + public static final int ERROR_SERVER_DISCONNECTED = 11; + /** action codes */ private final static int MSG_START = 1; private final static int MSG_STOP = 2; @@ -116,9 +121,6 @@ public class SpeechRecognizer { /** The actual RecognitionService endpoint */ private IRecognitionService mService; - /** The connection to the actual service */ - private Connection mConnection; - /** Context with which the manager was created */ private final Context mContext; @@ -151,15 +153,11 @@ public class SpeechRecognizer { } }; - /** - * Temporary queue, saving the messages until the connection will be established, afterwards, - * only mHandler will receive the messages - */ - private final Queue<Message> mPendingTasks = new LinkedList<Message>(); - /** The Listener that will receive all the callbacks */ private final InternalListener mListener = new InternalListener(); + private final IBinder mClientToken = new Binder(); + /** * The right way to create a {@code SpeechRecognizer} is by using * {@link #createSpeechRecognizer} static factory method @@ -181,30 +179,6 @@ public class SpeechRecognizer { } /** - * Basic ServiceConnection that records the mService variable. Additionally, on creation it - * invokes the {@link IRecognitionService#startListening(Intent, IRecognitionListener)}. - */ - private class Connection implements ServiceConnection { - - public void onServiceConnected(final ComponentName name, final IBinder service) { - // always done on the application main thread, so no need to send message to mHandler - mService = IRecognitionService.Stub.asInterface(service); - if (DBG) Log.d(TAG, "onServiceConnected - Success"); - while (!mPendingTasks.isEmpty()) { - mHandler.sendMessage(mPendingTasks.poll()); - } - } - - public void onServiceDisconnected(final ComponentName name) { - // always done on the application main thread, so no need to send message to mHandler - mService = null; - mConnection = null; - mPendingTasks.clear(); - if (DBG) Log.d(TAG, "onServiceDisconnected - Success"); - } - } - - /** * Checks whether a speech recognition service is available on the system. If this method * returns {@code false}, {@link SpeechRecognizer#createSpeechRecognizer(Context)} will * fail. @@ -303,87 +277,52 @@ public class SpeechRecognizer { throw new IllegalArgumentException("intent must not be null"); } checkIsCalledFromMainThread(); - if (mConnection == null) { // first time connection - // TODO(b/176578753): both flows should go through system service. - if (mOnDevice) { - connectToSystemService(); - } else { - connectToService(); - } - } - putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent)); - } - private void connectToSystemService() { - mManagerService = IRecognitionServiceManager.Stub.asInterface( - ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE)); - - if (mManagerService == null) { - mListener.onError(ERROR_CLIENT); - return; - } - - try { - // TODO(b/176578753): this has to supply information on whether to use on-device impl. - mManagerService.createSession(new IRecognitionServiceManagerCallback.Stub(){ - @Override - public void onSuccess(IRecognitionService service) throws RemoteException { - mService = service; - } - - @Override - public void onError() throws RemoteException { - Log.e(TAG, "Bind to system recognition service failed"); - mListener.onError(ERROR_CLIENT); - } - }); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - private void connectToService() { - mConnection = new Connection(); - - Intent serviceIntent = new Intent(RecognitionService.SERVICE_INTERFACE); - - if (mServiceComponent == null) { - String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE); - - if (TextUtils.isEmpty(serviceComponent)) { - Log.e(TAG, "no selected voice recognition service"); - mListener.onError(ERROR_CLIENT); - return; + if (DBG) { + Slog.i(TAG, "#startListening called"); + if (mService == null) { + Slog.i(TAG, "Connection is not established yet"); } + } - serviceIntent.setComponent( - ComponentName.unflattenFromString(serviceComponent)); + if (mService == null) { + // First time connection: first establish a connection, then dispatch #startListening. + connectToSystemService( + () -> putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent))); } else { - serviceIntent.setComponent(mServiceComponent); - } - if (!mContext.bindService(serviceIntent, mConnection, - Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES)) { - Log.e(TAG, "bind to recognition service failed"); - mConnection = null; - mService = null; - mListener.onError(ERROR_CLIENT); - return; + putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent)); } } /** * Stops listening for speech. Speech captured so far will be recognized as if the user had - * stopped speaking at this point. Note that in the default case, this does not need to be - * called, as the speech endpointer will automatically stop the recognizer listening when it - * determines speech has completed. However, you can manipulate endpointer parameters directly - * using the intent extras defined in {@link RecognizerIntent}, in which case you may sometimes - * want to manually call this method to stop listening sooner. Please note that + * stopped speaking at this point. + * + * <p>Note that in the default case, this does not need to be called, as the speech endpointer + * will automatically stop the recognizer listening when it determines speech has completed. + * However, you can manipulate endpointer parameters directly using the intent extras defined in + * {@link RecognizerIntent}, in which case you may sometimes want to manually call this method + * to stop listening sooner. + * + * <p>Upon invocation clients must wait until {@link RecognitionListener#onResults} or + * {@link RecognitionListener#onError} are invoked before calling + * {@link SpeechRecognizer#startListening} again. Otherwise such an attempt would be rejected by + * recognition service. + * + * <p>Please note that * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise * no notifications will be received. */ public void stopListening() { checkIsCalledFromMainThread(); + + if (DBG) { + Slog.i(TAG, "#stopListening called"); + if (mService == null) { + Slog.i(TAG, "Connection is not established yet"); + } + } + putMessage(Message.obtain(mHandler, MSG_STOP)); } @@ -405,11 +344,7 @@ public class SpeechRecognizer { } private void putMessage(Message msg) { - if (mService == null) { - mPendingTasks.offer(msg); - } else { - mHandler.sendMessage(msg); - } + mHandler.sendMessage(msg); } /** sends the actual message to the service */ @@ -419,7 +354,7 @@ public class SpeechRecognizer { } try { mService.startListening(recognizerIntent, mListener, mContext.getOpPackageName(), - mContext.getAttributionTag()); + mContext.getAttributionTag(), android.os.Process.myUid()); if (DBG) Log.d(TAG, "service start listening command succeded"); } catch (final RemoteException e) { Log.e(TAG, "startListening() failed", e); @@ -448,7 +383,11 @@ public class SpeechRecognizer { return; } try { - mService.cancel(mListener, mContext.getOpPackageName(), mContext.getAttributionTag()); + mService.cancel( + mListener, + mContext.getOpPackageName(), + mContext.getAttributionTag(), + false /* isShutdown */); if (DBG) Log.d(TAG, "service cancel command succeded"); } catch (final RemoteException e) { Log.e(TAG, "cancel() failed", e); @@ -471,28 +410,94 @@ public class SpeechRecognizer { mListener.mInternalListener = listener; } - /** - * Destroys the {@code SpeechRecognizer} object. - */ + /** Destroys the {@code SpeechRecognizer} object. */ public void destroy() { if (mService != null) { try { mService.cancel(mListener, mContext.getOpPackageName(), - mContext.getAttributionTag()); + mContext.getAttributionTag(), true /* isShutdown */); } catch (final RemoteException e) { // Not important } } - if (mConnection != null) { - mContext.unbindService(mConnection); - } - mPendingTasks.clear(); mService = null; - mConnection = null; mListener.mInternalListener = null; } + /** Establishes a connection to system server proxy and initializes the session. */ + private void connectToSystemService(Runnable onSuccess) { + mManagerService = IRecognitionServiceManager.Stub.asInterface( + ServiceManager.getService(Context.SPEECH_RECOGNITION_SERVICE)); + + if (mManagerService == null) { + mListener.onError(ERROR_CLIENT); + return; + } + + ComponentName componentName = getSpeechRecognizerComponentName(); + + if (!mOnDevice && componentName == null) { + mListener.onError(ERROR_CLIENT); + return; + } + + try { + mManagerService.createSession( + componentName, + mClientToken, + mOnDevice, + new IRecognitionServiceManagerCallback.Stub(){ + @Override + public void onSuccess(IRecognitionService service) throws RemoteException { + mService = service; + onSuccess.run(); + } + + @Override + public void onError(int errorCode) throws RemoteException { + Log.e(TAG, "Bind to system recognition service failed"); + mListener.onError(errorCode); + } + }); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** + * Returns the component name to be used for establishing a connection, based on the parameters + * used during initialization. + * + * <p>Note the 3 different scenarios: + * <ol> + * <li>On-device speech recognizer which is determined by the manufacturer and not + * changeable by the user + * <li>Default user-selected speech recognizer as specified by + * {@code Settings.Secure.VOICE_RECOGNITION_SERVICE} + * <li>Custom speech recognizer supplied by the client. + */ + private ComponentName getSpeechRecognizerComponentName() { + if (mOnDevice) { + return null; + } + + if (mServiceComponent != null) { + return mServiceComponent; + } + + String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE); + + if (TextUtils.isEmpty(serviceComponent)) { + Log.e(TAG, "no selected voice recognition service"); + mListener.onError(ERROR_CLIENT); + return null; + } + + return ComponentName.unflattenFromString(serviceComponent); + } + /** * Internal wrapper of IRecognitionListener which will propagate the results to * RecognitionListener diff --git a/core/java/android/uwb/OWNERS b/core/java/android/uwb/OWNERS index ea41c3984dfd..17936ae7bb73 100644 --- a/core/java/android/uwb/OWNERS +++ b/core/java/android/uwb/OWNERS @@ -1,5 +1,6 @@ bstack@google.com eliptus@google.com jsolnit@google.com +matbev@google.com siyuanh@google.com zachoverflow@google.com diff --git a/core/java/android/uwb/TEST_MAPPING b/core/java/android/uwb/TEST_MAPPING index 9e50bd64d089..08ed2c7b71d9 100644 --- a/core/java/android/uwb/TEST_MAPPING +++ b/core/java/android/uwb/TEST_MAPPING @@ -2,6 +2,9 @@ "presubmit": [ { "name": "UwbManagerTests" + }, + { + "name": "CtsUwbTestCases" } ] -}
\ No newline at end of file +} diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 62f4b864c7a8..4e4ba3fad246 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -32,7 +32,6 @@ import android.graphics.Region; import android.os.Bundle; import android.os.IRemoteCallback; import android.os.ParcelFileDescriptor; -import android.service.screenshot.ScreenshotHash; import android.view.DisplayCutout; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; @@ -63,6 +62,8 @@ import android.view.AppTransitionAnimationSpec; import android.view.WindowContentFrameStats; import android.view.WindowManager; import android.view.SurfaceControl; +import android.view.displayhash.DisplayHash; +import android.view.displayhash.VerifiedDisplayHash; /** * System private interface to the window manager. @@ -757,23 +758,23 @@ interface IWindowManager void holdLock(in IBinder token, in int durationMs); /** - * Gets an array of support hashing algorithms that can be used to generate the hash of the - * screenshot. The String value of one algorithm should be used when requesting to generate - * the ScreenshotHash. + * Gets an array of support hash algorithms that can be used to generate a DisplayHash. The + * String value of one algorithm should be used when requesting to generate + * the DisplayHash. * - * @return a String array of supported hashing algorithms. + * @return a String array of supported hash algorithms. */ - String[] getSupportedScreenshotHashingAlgorithms(); + String[] getSupportedDisplayHashAlgorithms(); /** - * Validate the ScreenshotHash was generated by the system. The ScreenshotHash passed in - * should be the token generated when calling {@link IWindowSession#generateScreenshotHash} + * Validate the DisplayHash was generated by the system. The DisplayHash passed in should be + * the object generated when calling {@link IWindowSession#generateDisplayHash} * - * @param ScreenshotHash The token to verify that it was generated by the system. - * @return true if the token was generated by the system or false if the token cannot be - * verified. + * @param DisplayHash The hash to verify that it was generated by the system. + * @return a {@link VerifiedDisplayHash} if the hash was generated by the system or null + * if the token cannot be verified. */ - boolean verifyScreenshotHash(in ScreenshotHash screenshotHash); + VerifiedDisplayHash verifyDisplayHash(in DisplayHash displayHash); /** * Registers a listener for a {@link android.app.WindowContext} to handle configuration changes diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index dad932c2ee19..ce649cc7c2b2 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -22,7 +22,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.os.Bundle; -import android.service.screenshot.ScreenshotHash; +import android.os.RemoteCallback; import android.util.MergedConfiguration; import android.view.DisplayCutout; import android.view.InputChannel; @@ -337,14 +337,15 @@ interface IWindowSession { void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus); /** - * Generates an ScreenshotHash that can be used to validate whether specific content was on + * Generates an DisplayHash that can be used to validate whether specific content was on * screen. * - * @param window The token for the window where the view to screenshot is shown. - * @param boundsInWindow The size and position of the ads view in the window - * @param hashAlgorithm The String for the hashing algorithm to use based on values returned - * from {@link IWindowManager#getSupportedHashingAlgorithms()} + * @param window The token for the window to generate the hash of. + * @param boundsInWindow The size and position in the window of where to generate the hash. + * @param hashAlgorithm The String for the hash algorithm to use based on values returned + * from {@link IWindowManager#getSupportedDisplayHashAlgorithms()} + * @param callback The callback invoked to get the results of generateDisplayHash */ - ScreenshotHash generateScreenshotHash(IWindow window, in Rect boundsInWindow, - in String hashAlgorithm); + oneway void generateDisplayHash(IWindow window, in Rect boundsInWindow, + in String hashAlgorithm, in RemoteCallback callback); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 44d4d6b24f58..c46fbc7fb4c4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -18,6 +18,12 @@ package android.view; import static android.content.res.Resources.ID_NULL; import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; +import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; +import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; +import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; +import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; +import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; +import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; @@ -89,6 +95,7 @@ import android.os.IBinder; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -135,6 +142,9 @@ import android.view.autofill.AutofillValue; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureManager; import android.view.contentcapture.ContentCaptureSession; +import android.view.displayhash.DisplayHash; +import android.view.displayhash.DisplayHashManager; +import android.view.displayhash.DisplayHashResultCallback; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inspector.InspectableProperty; @@ -176,6 +186,7 @@ import java.util.Locale; import java.util.Map; import java.util.Queue; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; @@ -30707,4 +30718,71 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void onTranslationComplete(@NonNull TranslationRequest request) { // no-op } + + /** + * Called to generate a {@link DisplayHash} for this view. + * + * @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of + * the values returned from + * {@link DisplayHashManager#getSupportedHashAlgorithms()} + * @param bounds The bounds for the content within the View to generate the hash for. If + * bounds are null, the entire View's bounds will be used. If empty, it will + * invoke the callback + * {@link DisplayHashResultCallback#onDisplayHashError} with error + * {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS} + * @param executor The executor that the callback should be invoked on. + * @param callback The callback to handle the results of generating the display hash + */ + @Nullable + public void generateDisplayHash(@NonNull String hashAlgorithm, + @Nullable Rect bounds, @NonNull Executor executor, + @NonNull DisplayHashResultCallback callback) { + IWindowSession session = getWindowSession(); + if (session == null) { + callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); + return; + } + IWindow window = getWindow(); + if (window == null) { + callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); + return; + } + + Rect visibleBounds = new Rect(); + getGlobalVisibleRect(visibleBounds); + + if (bounds != null && bounds.isEmpty()) { + callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); + return; + } + + if (bounds != null) { + bounds.offset(visibleBounds.left, visibleBounds.top); + visibleBounds.intersectUnchecked(bounds); + } + + if (visibleBounds.isEmpty()) { + callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); + return; + } + + RemoteCallback remoteCallback = new RemoteCallback(result -> + executor.execute(() -> { + DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH); + int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, + DISPLAY_HASH_ERROR_UNKNOWN); + if (displayHash != null) { + callback.onDisplayHashResult(displayHash); + } else { + callback.onDisplayHashError(errorCode); + } + })); + + try { + session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); + } catch (RemoteException e) { + Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); + callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); + } + } } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 39d3c01dd409..7cc2db1c0dab 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -23,8 +23,8 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.os.IBinder; +import android.os.RemoteCallback; import android.os.RemoteException; -import android.service.screenshot.ScreenshotHash; import android.util.Log; import android.util.MergedConfiguration; import android.window.ClientWindowFrames; @@ -487,8 +487,7 @@ public class WindowlessWindowManager implements IWindowSession { } @Override - public ScreenshotHash generateScreenshotHash(IWindow window, Rect boundsInWindow, - String hashAlgorithm) { - return null; + public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, + RemoteCallback callback) { } } diff --git a/core/java/android/service/screenshot/ScreenshotHash.aidl b/core/java/android/view/displayhash/DisplayHash.aidl index a7c50db171a2..cabf57573fa0 100644 --- a/core/java/android/service/screenshot/ScreenshotHash.aidl +++ b/core/java/android/view/displayhash/DisplayHash.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,6 +14,6 @@ * limitations under the License. */ -package android.service.screenshot; +package android.view.displayhash; -parcelable ScreenshotHash; +parcelable DisplayHash; diff --git a/core/java/android/view/displayhash/DisplayHash.java b/core/java/android/view/displayhash/DisplayHash.java new file mode 100644 index 000000000000..41484865b98e --- /dev/null +++ b/core/java/android/view/displayhash/DisplayHash.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.displayhash; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.AnnotationValidations; + +/** + * The DisplayHash used to validate information about what was present on screen. + */ +public final class DisplayHash implements Parcelable { + /** + * The timestamp when the hash was generated. + */ + private final long mTimeMillis; + + /** + * The bounds of the requested area to generate the hash. This is in window space passed in + * by the client. + */ + @NonNull + private final Rect mBoundsInWindow; + + /** + * The selected hash algorithm that generated the image hash. + */ + @NonNull + private final String mHashAlgorithm; + + /** + * The image hash generated when creating the DisplayHash. + */ + @NonNull + private final byte[] mImageHash; + + /** + * The hmac generated by the system and used to verify whether this token was generated by + * the system. + */ + @NonNull + private final byte[] mHmac; + + /** + * Creates a new DisplayHash. + * + * @param timeMillis The timestamp when the hash was generated. + * @param boundsInWindow The bounds of the requested area to generate the hash. This is + * in window space passed in by the client. + * @param hashAlgorithm The selected hash algorithm that generated the image hash. + * @param imageHash The image hash generated when creating the DisplayHash. + * @param hmac The hmac generated by the system and used to verify whether this + * token was generated by + * the system. This should only be accessed by a system process. + * @hide + */ + @SystemApi + public DisplayHash(long timeMillis, @NonNull Rect boundsInWindow, + @NonNull String hashAlgorithm, @NonNull byte[] imageHash, @NonNull byte[] hmac) { + mTimeMillis = timeMillis; + mBoundsInWindow = boundsInWindow; + AnnotationValidations.validate(NonNull.class, null, mBoundsInWindow); + mHashAlgorithm = hashAlgorithm; + AnnotationValidations.validate(NonNull.class, null, mHashAlgorithm); + mImageHash = imageHash; + AnnotationValidations.validate(NonNull.class, null, mImageHash); + mHmac = hmac; + AnnotationValidations.validate(NonNull.class, null, mHmac); + } + + /** + * The timestamp when the hash was generated. + * + * @hide + */ + @SystemApi + public long getTimeMillis() { + return mTimeMillis; + } + + /** + * The bounds of the requested area to to generate the hash. This is in window space passed in + * by the client. + * + * @hide + */ + @SystemApi + @NonNull + public Rect getBoundsInWindow() { + return mBoundsInWindow; + } + + /** + * The selected hash algorithm that generated the image hash. + * + * @hide + */ + @SystemApi + @NonNull + public String getHashAlgorithm() { + return mHashAlgorithm; + } + + /** + * The image hash generated when creating the DisplayHash. + * + * @hide + */ + @SystemApi + @NonNull + public byte[] getImageHash() { + return mImageHash; + } + + /** + * The hmac generated by the system and used to verify whether this token was generated by + * the system. This should only be accessed by a system process. + * + * @hide + */ + @SystemApi + @NonNull + public byte[] getHmac() { + return mHmac; + } + + /** @hide **/ + @Override + public String toString() { + return "DisplayHash { " + + "timeMillis = " + mTimeMillis + ", " + + "boundsInWindow = " + mBoundsInWindow + ", " + + "hashAlgorithm = " + mHashAlgorithm + ", " + + "imageHash = " + byteArrayToString(mImageHash) + ", " + + "hmac = " + byteArrayToString(mHmac) + + " }"; + } + + private String byteArrayToString(byte[] byteArray) { + if (byteArray == null) { + return "null"; + } + int iMax = byteArray.length - 1; + if (iMax == -1) { + return "[]"; + } + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + String formatted = String.format("%02X", byteArray[i] & 0xFF); + b.append(formatted); + if (i == iMax) { + return b.append(']').toString(); + } + b.append(", "); + } + } + + /** @hide **/ + @SystemApi + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mTimeMillis); + dest.writeTypedObject(mBoundsInWindow, flags); + dest.writeString(mHashAlgorithm); + dest.writeByteArray(mImageHash); + dest.writeByteArray(mHmac); + } + + /** @hide **/ + @SystemApi + @Override + public int describeContents() { + return 0; + } + + private DisplayHash(@NonNull Parcel in) { + mTimeMillis = in.readLong(); + Rect boundsInWindow = in.readTypedObject(Rect.CREATOR); + String hashAlgorithm = in.readString(); + byte[] imageHash = in.createByteArray(); + byte[] hmac = in.createByteArray(); + + mBoundsInWindow = boundsInWindow; + AnnotationValidations.validate(NonNull.class, null, mBoundsInWindow); + mHashAlgorithm = hashAlgorithm; + AnnotationValidations.validate(NonNull.class, null, mHashAlgorithm); + mImageHash = imageHash; + AnnotationValidations.validate(NonNull.class, null, mImageHash); + mHmac = hmac; + AnnotationValidations.validate(NonNull.class, null, mHmac); + } + + @NonNull + public static final Parcelable.Creator<DisplayHash> CREATOR = + new Parcelable.Creator<DisplayHash>() { + @Override + public DisplayHash[] newArray(int size) { + return new DisplayHash[size]; + } + + @Override + public DisplayHash createFromParcel(@NonNull Parcel in) { + return new DisplayHash(in); + } + }; +} diff --git a/core/java/android/view/displayhash/DisplayHashManager.java b/core/java/android/view/displayhash/DisplayHashManager.java new file mode 100644 index 000000000000..6b0c1a6d7633 --- /dev/null +++ b/core/java/android/view/displayhash/DisplayHashManager.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.displayhash; + + +import static android.content.Context.DISPLAY_HASH_SERVICE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemService; +import android.os.RemoteException; +import android.util.ArraySet; +import android.util.Log; +import android.view.WindowManagerGlobal; + +import com.android.internal.annotations.GuardedBy; + +import java.util.Collections; +import java.util.Set; + +/** + * Utility class for DisplayHash requests. + */ +@SystemService(DISPLAY_HASH_SERVICE) +public final class DisplayHashManager { + private static final String TAG = "DisplayHashManager"; + + private final Object mSupportedHashingAlgorithmLock = new Object(); + + @GuardedBy("mSupportedAlgorithmLock") + private static Set<String> sSupportedHashAlgorithms; + + /** + * @hide + */ + public DisplayHashManager() { + } + + /** + * Get a Set of DisplayHash algorithms that the device supports. + * + * @return a String Set of supported hashing algorithms. The String value of one + * algorithm should be used when requesting to generate the DisplayHash. + */ + @NonNull + public Set<String> getSupportedHashAlgorithms() { + synchronized (mSupportedHashingAlgorithmLock) { + if (sSupportedHashAlgorithms != null) { + return sSupportedHashAlgorithms; + } + + try { + String[] supportedAlgorithms = WindowManagerGlobal.getWindowManagerService() + .getSupportedDisplayHashAlgorithms(); + if (supportedAlgorithms == null) { + return Collections.emptySet(); + } + sSupportedHashAlgorithms = new ArraySet<>(supportedAlgorithms); + return sSupportedHashAlgorithms; + } catch (RemoteException e) { + Log.e(TAG, "Failed to send request getSupportedHashingAlgorithms", e); + return Collections.emptySet(); + } + } + } + + /** + * Call to verify that the DisplayHash passed in was generated by the system. + * + * @param displayHash The hash to verify that it was generated by the system. + * @return a {@link VerifiedDisplayHash} if the hash was generated by the system or null + * if the hash cannot be verified. + */ + @Nullable + public VerifiedDisplayHash verifyDisplayHash(@NonNull DisplayHash displayHash) { + try { + return WindowManagerGlobal.getWindowManagerService().verifyDisplayHash(displayHash); + } catch (RemoteException e) { + Log.e(TAG, "Failed to send request verifyImpressionToken", e); + return null; + } + } +} diff --git a/core/java/android/view/displayhash/DisplayHashResultCallback.java b/core/java/android/view/displayhash/DisplayHashResultCallback.java new file mode 100644 index 000000000000..15b29adafddd --- /dev/null +++ b/core/java/android/view/displayhash/DisplayHashResultCallback.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.displayhash; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.graphics.Rect; +import android.view.View; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; + +/** + * Use when calling {@link View#generateDisplayHash(String, Rect, Executor, + * DisplayHashResultCallback)}. + * + * The callback will only invoke either {@link #onDisplayHashResult} when the system successfully + * generated the {@link DisplayHash} or {@link #onDisplayHashError(int)} when it failed. + */ +public interface DisplayHashResultCallback { + /** + * @hide + */ + String EXTRA_DISPLAY_HASH = "DISPLAY_HASH"; + + /** + * @hide + */ + String EXTRA_DISPLAY_HASH_ERROR_CODE = "DISPLAY_HASH_ERROR_CODE"; + + /** + * An unknown error occurred. + */ + int DISPLAY_HASH_ERROR_UNKNOWN = -1; + + /** + * The bounds used when requesting the hash hash were invalid or empty. + */ + int DISPLAY_HASH_ERROR_INVALID_BOUNDS = -2; + + /** + * The window for the view that requested the hash is no longer around. This can happen if the + * window is getting torn down. + */ + int DISPLAY_HASH_ERROR_MISSING_WINDOW = -3; + + /** + * The view that requested the hash is not visible on screen. This could either mean + * that the view bounds are offscreen, window bounds are offscreen, view is not visible, or + * window is not visible. + */ + int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4; + + /** @hide */ + @IntDef(prefix = {"DISPLAY_HASH_ERROR_"}, value = { + DISPLAY_HASH_ERROR_UNKNOWN, + DISPLAY_HASH_ERROR_INVALID_BOUNDS, + DISPLAY_HASH_ERROR_MISSING_WINDOW, + DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN + }) + @Retention(RetentionPolicy.SOURCE) + @interface DisplayHashErrorCode { + } + + /** + * Callback invoked when calling + * {@link android.view.View#generateDisplayHash(String, Rect, Executor, + * DisplayHashResultCallback)} + * + * @param displayHash The DisplayHash generated. If the hash cannot be generated, + * {@link #onDisplayHashError(int)} will be called instead + */ + void onDisplayHashResult(@NonNull DisplayHash displayHash); + + /** + * Callback invoked when + * {@link android.view.View#generateDisplayHash(String, Rect, Executor, + * DisplayHashResultCallback)} results in an error and cannot generate a display hash. + * + * @param errorCode One of the values in {@link DisplayHashErrorCode} + */ + void onDisplayHashError(@DisplayHashErrorCode int errorCode); +} diff --git a/core/java/android/view/displayhash/OWNERS b/core/java/android/view/displayhash/OWNERS new file mode 100644 index 000000000000..0862c05e0ee4 --- /dev/null +++ b/core/java/android/view/displayhash/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/wm/OWNERS diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java b/core/java/android/view/displayhash/VerifiedDisplayHash.aidl index c4be1ba53503..9e7ebefa7ca1 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockModule.java +++ b/core/java/android/view/displayhash/VerifiedDisplayHash.aidl @@ -14,20 +14,6 @@ * limitations under the License. */ -package com.android.keyguard.clock; +package android.view.displayhash; -import java.util.List; - -import dagger.Module; -import dagger.Provides; - -/** Dagger Module for clock package. */ -@Module -public abstract class ClockModule { - - /** */ - @Provides - public static List<ClockInfo> provideClockInfoList(ClockManager clockManager) { - return clockManager.getClockInfos(); - } -} +parcelable VerifiedDisplayHash; diff --git a/core/java/android/view/displayhash/VerifiedDisplayHash.java b/core/java/android/view/displayhash/VerifiedDisplayHash.java new file mode 100644 index 000000000000..16a428e73005 --- /dev/null +++ b/core/java/android/view/displayhash/VerifiedDisplayHash.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.displayhash; + +import android.annotation.NonNull; +import android.graphics.Rect; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * The verified display hash used to validate information about what was present on screen. + */ +@DataClass(genToString = true, genAidl = true) +public final class VerifiedDisplayHash implements Parcelable { + /** + * The timestamp when the hash was generated. + */ + private final long mTimeMillis; + + /** + * The bounds of the requested area to generate the hash. This is in window space passed in + * by the client. + */ + @NonNull + private final Rect mBoundsInWindow; + + /** + * The selected hash algorithm that generated the image hash. + */ + @NonNull + private final String mHashAlgorithm; + + /** + * The image hash generated when creating the DisplayHash. + */ + @NonNull + private final byte[] mImageHash; + + private String imageHashToString() { + return byteArrayToString(mImageHash); + } + + private String byteArrayToString(byte[] byteArray) { + if (byteArray == null) { + return "null"; + } + int iMax = byteArray.length - 1; + if (iMax == -1) { + return "[]"; + } + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + String formatted = String.format("%02X", byteArray[i] & 0xFF); + b.append(formatted); + if (i == iMax) { + return b.append(']').toString(); + } + b.append(", "); + } + } + + + + // Code below generated by codegen v1.0.22. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/displayhash/VerifiedDisplayHash.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new VerifiedDisplayHash. + * + * @param timeMillis + * The timestamp when the hash was generated. + * @param boundsInWindow + * The bounds of the requested area to generate the hash. This is in window space passed in + * by the client. + * @param hashAlgorithm + * The selected hash algorithm that generated the image hash. + * @param imageHash + * The image hash generated when creating the DisplayHash. + */ + @DataClass.Generated.Member + public VerifiedDisplayHash( + long timeMillis, + @NonNull Rect boundsInWindow, + @NonNull String hashAlgorithm, + @NonNull byte[] imageHash) { + this.mTimeMillis = timeMillis; + this.mBoundsInWindow = boundsInWindow; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mBoundsInWindow); + this.mHashAlgorithm = hashAlgorithm; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHashAlgorithm); + this.mImageHash = imageHash; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mImageHash); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The timestamp when the hash was generated. + */ + @DataClass.Generated.Member + public long getTimeMillis() { + return mTimeMillis; + } + + /** + * The bounds of the requested area to generate the hash. This is in window space passed in + * by the client. + */ + @DataClass.Generated.Member + public @NonNull Rect getBoundsInWindow() { + return mBoundsInWindow; + } + + /** + * The selected hash algorithm that generated the image hash. + */ + @DataClass.Generated.Member + public @NonNull String getHashAlgorithm() { + return mHashAlgorithm; + } + + /** + * The image hash generated when creating the DisplayHash. + */ + @DataClass.Generated.Member + public @NonNull byte[] getImageHash() { + return mImageHash; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "VerifiedDisplayHash { " + + "timeMillis = " + mTimeMillis + ", " + + "boundsInWindow = " + mBoundsInWindow + ", " + + "hashAlgorithm = " + mHashAlgorithm + ", " + + "imageHash = " + imageHashToString() + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeLong(mTimeMillis); + dest.writeTypedObject(mBoundsInWindow, flags); + dest.writeString(mHashAlgorithm); + dest.writeByteArray(mImageHash); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ VerifiedDisplayHash(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + long timeMillis = in.readLong(); + Rect boundsInWindow = (Rect) in.readTypedObject(Rect.CREATOR); + String hashAlgorithm = in.readString(); + byte[] imageHash = in.createByteArray(); + + this.mTimeMillis = timeMillis; + this.mBoundsInWindow = boundsInWindow; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mBoundsInWindow); + this.mHashAlgorithm = hashAlgorithm; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHashAlgorithm); + this.mImageHash = imageHash; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mImageHash); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<VerifiedDisplayHash> CREATOR + = new Parcelable.Creator<VerifiedDisplayHash>() { + @Override + public VerifiedDisplayHash[] newArray(int size) { + return new VerifiedDisplayHash[size]; + } + + @Override + public VerifiedDisplayHash createFromParcel(@NonNull android.os.Parcel in) { + return new VerifiedDisplayHash(in); + } + }; + + @DataClass.Generated( + time = 1613168749684L, + codegenVersion = "1.0.22", + sourceFile = "frameworks/base/core/java/android/view/displayhash/VerifiedDisplayHash.java", + inputSignatures = "private final long mTimeMillis\nprivate final @android.annotation.NonNull android.graphics.Rect mBoundsInWindow\nprivate final @android.annotation.NonNull java.lang.String mHashAlgorithm\nprivate final @android.annotation.NonNull byte[] mImageHash\nprivate java.lang.String imageHashToString()\nprivate java.lang.String byteArrayToString(byte[])\nclass VerifiedDisplayHash extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genAidl=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp index 0f7611a8ead1..f67007cda209 100644 --- a/core/jni/android_os_Trace.cpp +++ b/core/jni/android_os_Trace.cpp @@ -83,7 +83,7 @@ static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass, } static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv*, jclass, jboolean allowed) { - atrace_set_debuggable(allowed); + atrace_update_tags(); } static void android_os_Trace_nativeSetTracingEnabled(JNIEnv*, jclass, jboolean enabled) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c61802d54e04..a4da22280bf1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5498,11 +5498,11 @@ android:protectionLevel="signature" /> <!-- Must be required by a - {@link android.service.screenshot.ScreenshotHasherService} + {@link android.service.displayhash.DisplayHasherService} to ensure that only the system can bind to it. @hide This is not a third-party API (intended for OEMs and system apps). --> - <permission android:name="android.permission.BIND_SCREENSHOT_HASHER_SERVICE" + <permission android:name="android.permission.BIND_DISPLAY_HASHER_SERVICE" android:protectionLevel="signature" /> <!-- @hide @TestApi Allows an application to enable/disable toast rate limiting. diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 55eaaf648f84..8aa297ec66e5 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor is tydelik gedeaktiveer."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gebruik jou vingerafdruk om voort te gaan"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdrukikoon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gebruik kortpad"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Kleuromkering"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurkorreksie"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Verminder helderheid"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aangeskakel."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Het volumesleutels ingehou. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is afgeskakel"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Druk en hou albei volumesleutels drie sekondes lank om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruik"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimeer"</string> <string name="close_button_text" msgid="10603510034455258">"Maak toe"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Antwoord"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Wys af"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Lui af"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Inkomende oproep"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Oproep aan die gang"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Keur tans \'n inkomende oproep"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> gekies</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 316122669352..16c8404ce1bd 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ጣት <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ለመቀጠል የእርስዎን የጣት አሻራ ይጠቀሙ"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"የጣት አሻራ አዶ"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"አቋራጭ ይጠቀሙ"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"ተቃራኒ ቀለም"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"የቀለም ማስተካከያ"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ብሩህነትን ይቀንሱ"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> በርቷል።"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ጠፍተዋል።"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ን ለመጠቀም ለሦስት ሰከንዶች ሁለቱንም የድምፅ ቁልፎች ተጭነው ይያዙ"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"አስፋ"</string> <string name="close_button_text" msgid="10603510034455258">"ዝጋ"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>፦ <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"መልስ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"አትቀበል"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ስልኩን ዝጋ"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ገቢ ጥሪ"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"እየተካሄደ ያለ ጥሪ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ገቢ ጥሪ ማጣራት"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጧል</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index a2d3671d667c..a291a89b62f8 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -152,8 +152,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi فقط"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> الاتصال الاحتياطي"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: لم تتم إعادة التوجيه"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> بعد <xliff:g id="TIME_DELAY">{2}</xliff:g> ثانية"</string> @@ -592,6 +591,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"تم إيقاف جهاز الاستشعار مؤقتًا."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"الإصبع <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"يمكنك استخدام بصمة الإصبع للمتابعة."</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"رمز بصمة الإصبع"</string> @@ -1753,6 +1753,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"استخدام الاختصار"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"قلب الألوان"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"تصحيح الألوان"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"تقليل السطوع"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم تفعيل <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"تم الضغط مع الاستمرار على مفتاحَي التحكّم في مستوى الصوت. تم إيقاف <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"اضغط مع الاستمرار على مفتاحي مستوى الصوت لمدة 3 ثوانٍ لاستخدام <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> @@ -2005,6 +2006,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"تكبير"</string> <string name="close_button_text" msgid="10603510034455258">"إغلاق"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"ردّ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"رفض"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"قطع الاتصال"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"مكالمة واردة"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"مكالمة جارية"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"رصد مكالمة واردة"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="zero">تم اختيار <xliff:g id="COUNT_1">%1$d</xliff:g> عنصر</item> <item quantity="two">تم اختيار عنصرين (<xliff:g id="COUNT_1">%1$d</xliff:g>)</item> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 0a9ef97c2ad8..3c052d74878b 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"কোৱল ৱাই-ফাই"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> বেকআপ কলিং"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফৰৱাৰ্ড কৰা নহ\'ল"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ছেকেণ্ডৰ পাছত"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> আঙুলি"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ফিংগাৰপ্ৰিণ্ট আইকন"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শ্বৰ্টকাট ব্যৱহাৰ কৰক"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"ৰং বিপৰীতকৰণ"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"ৰং শুধৰণী"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"উজ্জ্বলতা কমাওক"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কীসমূহ ধৰি ৰাখক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰা হ\'ল।"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধৰি ৰাখিছিল। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অফ কৰা হ\'ল।"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবলৈ দুয়োটা ভলিউম বুটাম তিনি ছেকেণ্ডৰ বাবে হেঁচি ৰাখক"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string> <string name="close_button_text" msgid="10603510034455258">"বন্ধ কৰক"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"উত্তৰ দিয়ক"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"প্ৰত্যাখ্যান কৰক"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"কল কাটি দিয়ক"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"অন্তৰ্গামী কল"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"চলি থকা কল"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"এটা অন্তৰ্গামী কলৰ পৰীক্ষা কৰি থকা হৈছে"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বাছনি কৰা হ’ল</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টা বাছনি কৰা হ’ল</item> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index e91e2b740543..70b57a99be1d 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -325,7 +325,7 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"Həyati əlamətlər haqqında sensor dataya daxil olun"</string> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Pəncərənin məzmununu əldə edin"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Əlaqədə olduğunuz pəncərənin məzmununu nəzərdən keçirin."</string> - <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Toxunaraq Kəşf et funksiyasını yandırın"</string> + <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Toxunuşla öyrənmə funksiyasını aktiv edin"</string> <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Tıklanan hissələr səsləndiriləcək və ekran jestlərlə idarə oluna biləcək."</string> <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Yazdığınız mətni izləyin"</string> <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Kredit kartı nömrələri və parollar kimi şəxsi məlumatlar daxildir."</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor müvəqqəti deaktivdir."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Davam etmək üçün barmaq izinizi istifadə edin"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmaq izi ikonası"</string> @@ -1629,7 +1630,7 @@ <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"Android TV cihazını kiliddən çıxarmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etdiniz. Android TV cihazınız defolt fabrik dəyərlərinə sıfırlanacaq."</string> <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Siz telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> yanlış cəhd etmisiniz. Telefon artıq defolt zavod halına sıfırlanacaq."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"Siz kilidi açmaq üçün şablonu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə səhv çəkdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> daha uğursuz cəhddən sonra planşetinizin kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə ərzində bir daha yoxlayın."</string> - <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Kiliddən çıxarma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> yanlış cəhddən sonra Android TV cihazını e-poçt hesabınızla kiliddən çıxarmağınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra yenidən cəhd edin."</string> + <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Kiliddən çıxarma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> yanlış cəhddən sonra Android TV cihazını e-poçt hesabınızla kiliddən çıxarmağınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Siz artıq modeli <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etmisiniz.<xliff:g id="NUMBER_1">%2$d</xliff:g> dəfə də yanlış daxil etsəniz, telefonun kilidinin açılması üçün elektron poçt ünvanınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə ərzində yenidən cəhd edin."</string> <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string> <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Yığışdır"</string> @@ -1637,10 +1638,10 @@ <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Əlçatımlılıq Qısayolu istifadə edilsin?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Qısayol aktiv olduqda, hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası başladılacaq."</string> <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Əlçatımlılıq funksiyaları üçün qısayol aktiv edilsin?"</string> - <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyaları aktiv olur. Bu, cihazınızın işləmə qaydasını dəyişə bilər.\n\nCari funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAyarlar və Əlçatımlılıq bölməsində seçilmiş funksiyaları dəyişə bilərsiniz."</string> + <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyaları aktiv olur. Cihazınızın işləmə qaydasını dəyişə bilər.\n\nCari funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAyarlar və Əlçatımlılıq bölməsində seçilmiş funksiyaları dəyişə bilərsiniz."</string> <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string> <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> qısayolu aktiv edilsin?"</string> - <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyası olan <xliff:g id="SERVICE">%1$s</xliff:g> aktiv olur. Bu, cihazınızın işləmə qaydasını dəyişə bilər.\n\nAyarlar və Əlçatımlılıq bölməsində bu qısayolu başqa bir funksiyata dəyişə bilərsiniz."</string> + <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyası olan <xliff:g id="SERVICE">%1$s</xliff:g> aktiv olur. Cihazınızın işləmə qaydasını dəyişə bilər.\n\nAyarlar və Əlçatımlılıq bölməsində bu qısayolu başqa bir funksiyaya dəyişə bilərsiniz."</string> <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktiv edin"</string> <string name="accessibility_shortcut_off" msgid="3651336255403648739">"Aktiv etməyin"</string> <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"AKTİV"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Qısayol İstifadə edin"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Rəng İnversiyası"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Rəng korreksiyası"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Parlaqlığı Azaldın"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Səs səviyyəsi düymələrinə basıb saxlayın. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktiv edildi."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Səs səviyyəsi düymələrinə basılaraq saxlanıb. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> deaktiv edilib."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> istifadə etmək üçün hər iki səs düyməsini üç saniyə basıb saxlayın"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Böyüdün"</string> <string name="close_button_text" msgid="10603510034455258">"Qapadın"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Cavab verin"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"İmtina edin"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Dəstəyi asın"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Gələn zəng"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Davam edən zəng"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Gələn zəng göstərilir"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seçilib</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seçilib</item> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index a490a6ce2b7d..c96264ead6dd 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -582,6 +582,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string> @@ -1686,6 +1687,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boja"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjite osvetljenost"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tastere za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite oba tastera za jačinu zvuka tri sekunde da biste koristili <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1911,6 +1913,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Uvećaj"</string> <string name="close_button_text" msgid="10603510034455258">"Zatvori"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Odgovori"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Odbij"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Prekini vezu"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Dolazni poziv"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Poziv je u toku"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Proverava se dolazni poziv"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one">Izabrana je <xliff:g id="COUNT_1">%1$d</xliff:g> stavka</item> <item quantity="few">Izabrane su <xliff:g id="COUNT_1">%1$d</xliff:g> stavke</item> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 80f67d07a0d2..06b7372665d0 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -150,8 +150,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Толькі Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Рэзервовае капіраванне выклікаў праз аператара \"<xliff:g id="SPN">%s</xliff:g>\""</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не пераадрасоўваецца"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> праз <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string> @@ -586,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Каб працягнуць, выкарыстоўвайце свой адбітак пальца"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок адбіткаў пальцаў"</string> @@ -1709,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Выкарыстоўваць камбінацыю хуткага доступу"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Інверсія колеру"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Карэкцыя колеру"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Паменшыць яркасць"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Клавішы гучнасці ўтрымліваліся націснутымі. Уключана служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Клавішы гучнасці ўтрымліваліся націснутымі. Служба \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" выключана."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Каб карыстацца сэрвісам \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", націсніце і ўтрымлівайце на працягу трох секунд абедзве клавішы гучнасці"</string> @@ -1943,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Разгарнуць"</string> <string name="close_button_text" msgid="10603510034455258">"Закрыць"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Адказаць"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Адхіліць"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Завяршыць"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Уваходны выклік"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Бягучы выклік"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Фільтраванне ўваходнага выкліку"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> выбраны</item> <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> выбрана</item> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 20342e07953d..3a86bea53b9b 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорът е временно деактивиран."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Пръст <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Използвайте отпечатъка си, за да продължите"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатък"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Използване на пряк път"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Инвертиране на цветовете"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Коригиране на цветовете"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Намаляване на яркостта"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е включена."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Задържахте бутоните за силата на звука. Услугата <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е изключена."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"За да използвате <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, натиснете двата бутона за силата на звука и ги задръжте за 3 секунди"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Увеличаване"</string> <string name="close_button_text" msgid="10603510034455258">"Затваряне"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"„<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>“: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Отговор"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Отхвърляне"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Затваряне"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Входящо обаждане"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Текущо обаждане"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Преглежда се входящо обаждане"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">Избрахте <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="one">Избрахте <xliff:g id="COUNT_0">%1$d</xliff:g></item> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 51d09b27afe6..2cb7bf544bab 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"শুধুমাত্র ওয়াই-ফাই"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> ব্যাক-আপ কলিং"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফরওয়ার্ড করা হয়নি"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> সেকেন্ড পরে"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"আঙ্গুল <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"চালিয়ে যেতে আঙ্গুলের ছাপ ব্যবহার করুন"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"আঙ্গুলের ছাপ আইকন"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শর্টকাট ব্যবহার করুন"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"রঙ উল্টানো"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"রঙ সংশোধন"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"উজ্জ্বলতা কমান"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> চালু করা হয়েছে।"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধরে ছিলেন। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> বন্ধ করা হয়েছে।"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ব্যবহার করতে ভলিউম কী বোতাম ৩ সেকেন্ডের জন্য চেপে ধরে রাখুন"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"বড় করুন"</string> <string name="close_button_text" msgid="10603510034455258">"বন্ধ করুন"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"উত্তর"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"বাতিল করুন"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"কল কেটে দেওয়া"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ইনকামিং কল"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"চালু থাকা কল"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ইনকামিং কল স্ক্রিনিং করা হচ্ছে"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 989e2bb7b598..b738b0d907a5 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -582,6 +582,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona za otisak prsta"</string> @@ -1686,6 +1687,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Koristi prečicu"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Ispravka boja"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjenje osvjetljenja"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je uključena."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za jačinu zvuka. Usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je isključena."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite obje tipke za podešavanje jačine zvuka i držite ih pritisnutim tri sekunde da koristite uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1911,6 +1913,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Povećaj maksimalno"</string> <string name="close_button_text" msgid="10603510034455258">"Zatvori"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Odgovori"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Odbaci"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Prekini vezu"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Dolazni poziv"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Poziv u toku"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtriranje dolaznog poziva"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> stavka je odabrana</item> <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index e9c55d76c6ac..ead0988d9b8d 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -538,10 +538,10 @@ <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permet que l\'aplicació conegui el nivell de complexitat del bloqueig de pantalla (alt, mitjà, baix o cap), que indica la llargària i el tipus de bloqueig de pantalla possibles. L\'aplicació també pot suggerir que els usuaris actualitzin el bloqueig de pantalla a un nivell determinat, però els usuaris poden ignorar aquestes recomanacions. Tingues en compte que el bloqueig de pantalla no s\'emmagatzema com a text sense format, de manera que l\'aplicació no coneix la contrasenya exacta."</string> <string name="permlab_useBiometric" msgid="6314741124749633786">"utilitza maquinari biomètric"</string> <string name="permdesc_useBiometric" msgid="7502858732677143410">"Permet que l\'aplicació faci servir maquinari biomètric per a l\'autenticació"</string> - <string name="permlab_manageFingerprint" msgid="7432667156322821178">"Gestionar el maquinari d\'empremtes dactilars"</string> + <string name="permlab_manageFingerprint" msgid="7432667156322821178">"Gestionar el maquinari d\'empremtes digitals"</string> <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permet que l\'aplicació invoqui mètodes per afegir i suprimir plantilles d\'empremtes dactilars que es puguin fer servir."</string> - <string name="permlab_useFingerprint" msgid="1001421069766751922">"Utilitzar el maquinari d\'empremtes dactilars"</string> - <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permet que l\'aplicació faci servir maquinari d\'empremtes dactilars per a l\'autenticació"</string> + <string name="permlab_useFingerprint" msgid="1001421069766751922">"Utilitzar el maquinari d\'empremtes digitals"</string> + <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permet que l\'aplicació faci servir maquinari d\'empremtes digitals per a l\'autenticació"</string> <string name="permlab_audioWrite" msgid="8501705294265669405">"modificar la teva col·lecció de música"</string> <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permet que l\'aplicació modifiqui la teva col·lecció de música."</string> <string name="permlab_videoWrite" msgid="5940738769586451318">"modificar la teva col·lecció de vídeos"</string> @@ -567,7 +567,7 @@ <string name="fingerprint_authenticated" msgid="2024862866860283100">"L\'empremta digital s\'ha autenticat"</string> <string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"Cara autenticada"</string> <string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"Cara autenticada; prem el botó per confirmar"</string> - <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"El maquinari per a empremtes dactilars no està disponible."</string> + <string name="fingerprint_error_hw_not_available" msgid="4571700896929561202">"El maquinari d\'empremtes digitals no està disponible."</string> <string name="fingerprint_error_no_space" msgid="6126456006769817485">"L\'empremta digital no es pot desar. Suprimeix-ne una."</string> <string name="fingerprint_error_timeout" msgid="2946635815726054226">"S\'ha esgotat el temps d\'espera per a l\'empremta digital. Torna-ho a provar."</string> <string name="fingerprint_error_canceled" msgid="540026881380070750">"S\'ha cancel·lat l\'operació d\'empremta digital."</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes dactilars."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor està desactivat temporalment."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Fes servir l\'empremta digital per continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona d\'empremta digital"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilitza la drecera"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversió de colors"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Correcció de color"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducció de la brillantor"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S\'han mantingut premudes les tecles de volum. S\'ha activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S\'han mantingut premudes les tecles de volum. S\'ha desactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premudes les dues tecles de volum durant 3 segons per fer servir <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximitza"</string> <string name="close_button_text" msgid="10603510034455258">"Tanca"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Respon"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Rebutja"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Penja"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Trucada entrant"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Trucada en curs"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"S\'està filtrant una trucada entrant"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">Seleccionats: <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="one">Seleccionats: <xliff:g id="COUNT_0">%1$d</xliff:g></item> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 071bbfd69ce5..a9975b5a4fd0 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -585,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasně deaktivován."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Pokračujte přiložením prstu"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otisku prstů"</string> @@ -1708,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použít zkratku"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Převrácení barev"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Oprava barev"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Snížit jas"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Chcete-li používat službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, tři sekundy podržte stisknutá obě tlačítka hlasitosti"</string> @@ -1942,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximalizovat"</string> <string name="close_button_text" msgid="10603510034455258">"Zavřít"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Přijmout"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Odmítnout"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Zavěsit"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Příchozí hovor"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Probíhající hovor"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Prověřování příchozího hovoru"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> položky</item> <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> položky</item> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index b760f5b1c16e..187e098b869f 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -148,7 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Kun Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Alternativ løsning til opkald leveret af <xliff:g id="SPN">%s</xliff:g>"</string> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g>-opkald via alternativt SIM"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderestillet"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string> @@ -581,6 +581,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidigt deaktiveret."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Brug dit fingeraftryk for at fortsætte"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeraftryk"</string> @@ -1666,6 +1667,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Brug genvej"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Ombytning af farver"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Korriger farve"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducer lysstyrken"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er aktiveret."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lydstyrkeknapperne blev holdt nede. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er deaktiveret."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Hold begge lydstyrkeknapper nede i tre sekunder for at bruge <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1882,6 +1884,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimér"</string> <string name="close_button_text" msgid="10603510034455258">"Luk"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Besvar"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Afvis"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Læg på"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Indgående opkald"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Igangværende opkald"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Et indgående opkald screenes"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>valgt</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index f8066e2bfedf..f8e874dd3d61 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Nur WLAN"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g>-Anruf über Ersatz-SIM"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dieses Gerät hat keinen Fingerabdrucksensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Der Sensor ist vorübergehend deaktiviert."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Mithilfe deines Fingerabdrucks fortfahren"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerabdruck-Symbol"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Verknüpfung verwenden"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Farbumkehr"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Farbkorrektur"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Helligkeit verringern"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist aktiviert."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist deaktiviert."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximieren"</string> <string name="close_button_text" msgid="10603510034455258">"Schließen"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Annehmen"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Ablehnen"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Auflegen"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Eingehender Anruf"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Aktueller Anruf"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Screening für eingehenden Anruf"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ausgewählt</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ausgewählt</item> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 4f3c8a95a469..14d0271578c8 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Δάχτυλο <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Χρησιμοποιήστε το δακτυλικό αποτύπωμά σας για να συνεχίσετε"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Χρήση συντόμευσης"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Αντιστροφή χρωμάτων"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Διόρθωση χρωμάτων"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Μείωση φωτεινότητας"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ενεργοποιήθηκε."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>: απενεργοποιημένο"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Πατήστε παρατεταμένα και τα δύο κουμπιά έντασης ήχου για τρία δευτερόλεπτα, ώστε να χρησιμοποιήσετε την υπηρεσία <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Μεγιστοποίηση"</string> <string name="close_button_text" msgid="10603510034455258">"Κλείσιμο"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Απάντηση"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Απόρριψη"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Τερματισμός"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Εισερχόμενη κλήση"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Κλήση σε εξέλιξη"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Διαλογή εισερχόμενης κλήσης"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">Επιλέχτηκαν <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="one">Επιλέχτηκε <xliff:g id="COUNT_0">%1$d</xliff:g></item> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 9f3bc7de2385..6c850a6ded1b 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximise"</string> <string name="close_button_text" msgid="10603510034455258">"Close"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Answer"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Decline"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Hang up"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Incoming call"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"On-going call"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Screening an incoming call"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 766e372927d6..dd37df765aa5 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour inversion"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximise"</string> <string name="close_button_text" msgid="10603510034455258">"Close"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Answer"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Decline"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Hang up"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Incoming call"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"On-going call"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Screening an incoming call"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 16da2116ed40..17dbd45f2395 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Colour correction"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximise"</string> <string name="close_button_text" msgid="10603510034455258">"Close"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Answer"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Decline"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Hang up"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Incoming call"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"On-going call"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Screening an incoming call"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 150830ef027d..fb57bbcd5a2e 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Colour Inversion"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Color correction"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximise"</string> <string name="close_button_text" msgid="10603510034455258">"Close"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Answer"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Decline"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Hang up"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Incoming call"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"On-going call"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Screening an incoming call"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index e952cac93ca6..8fbeedeb8fea 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use your fingerprint to continue"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Use Shortcut"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Color Inversion"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Color Correction"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduce Brightness"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned on."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Held volume keys. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> turned off."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Press and hold both volume keys for three seconds to use <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximize"</string> <string name="close_button_text" msgid="10603510034455258">"Close"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Answer"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Decline"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Hang Up"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Incoming call"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Ongoing call"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Screening an incoming call"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index c5ff193bc6a2..3e995c6e6d34 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza tu huella digital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella digital"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar acceso directo"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir el brillo"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Como mantuviste presionadas las teclas de volumen, se activó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se presionaron las teclas de volumen. Se desactivó <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén presionadas ambas teclas de volumen durante tres segundos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizar"</string> <string name="close_button_text" msgid="10603510034455258">"Cerrar"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Responder"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Rechazar"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Colgar"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Llamada entrante"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Llamada en curso"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando una llamada entrante"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> elementos seleccionados</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento seleccionado</item> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 108c3dbeb954..8b1c3271e7f5 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor está inhabilitado en estos momentos."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Usa tu huella digital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icono de huella digital"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar acceso directo"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de color"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de color"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir brillo"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Al mantener pulsadas las teclas de volumen, se ha activado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Se han mantenido pulsadas las teclas de volumen. Se ha desactivado <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Para utilizar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, mantén pulsadas ambas teclas de volumen durante 3 segundos"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizar"</string> <string name="close_button_text" msgid="10603510034455258">"Cerrar"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Responder"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Rechazar"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Colgar"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Llamada entrante"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Llamada en curso"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando una llamada entrante"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seleccionados</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 70862d481b65..33f8e526828a 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Jätkamiseks kasutage sõrmejälge"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sõrmejälje ikoon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kasuta otseteed"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Värvide ümberpööramine"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Värvide korrigeerimine"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Ereduse vähendamine"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati sisse."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Helitugevuse klahve hoiti all. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> lülitati välja."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Teenuse <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kasutamiseks hoidke kolm sekundit all mõlemat helitugevuse klahvi"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimeeri"</string> <string name="close_button_text" msgid="10603510034455258">"Sule"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Vasta"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Keeldu"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Lõpeta kõne"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Sissetulev kõne"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Käimasolev kõne"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Sissetuleva kõne filtreerimine"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> on valitud</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index bc691a5c37e2..8328c86df751 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -93,7 +93,7 @@ <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Datu-konexioaren egoera"</string> <string name="notification_channel_sms" msgid="1243384981025535724">"SMS mezuak"</string> <string name="notification_channel_voice_mail" msgid="8457433203106654172">"Erantzungailuko mezuak"</string> - <string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi bidezko deiak"</string> + <string name="notification_channel_wfc" msgid="9048240466765169038">"Wifi bidezko deiak"</string> <string name="notification_channel_sim" msgid="5098802350325677490">"SIMaren egoera"</string> <string name="notification_channel_sim_high_prio" msgid="642361929452850928">"SIM txartelaren lehentasun handiko jakinarazpenak"</string> <string name="peerTtyModeFull" msgid="337553730440832160">"Beste gailuak TTY osagarria FULL moduan erabiltzea eskatu du"</string> @@ -122,23 +122,23 @@ <string name="roamingText11" msgid="5245687407203281407">"Ibiltaritzari buruzko jakinarazpena aktibatuta"</string> <string name="roamingText12" msgid="673537506362152640">"Ibiltaritzari buruzko jakinarazpena desaktibatuta"</string> <string name="roamingTextSearching" msgid="5323235489657753486">"Zerbitzu bila"</string> - <string name="wfcRegErrorTitle" msgid="3193072971584858020">"Ezin izan dira konfiguratu Wi‑Fi bidezko deiak"</string> + <string name="wfcRegErrorTitle" msgid="3193072971584858020">"Ezin izan dira konfiguratu wifi bidezko deiak"</string> <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="468830943567116703">"Wi-Fi bidez deiak egiteko eta mezuak bidaltzeko, eskatu operadoreari zerbitzu hori gaitzeko. Ondoren, aktibatu Wi-Fi bidezko deiak Ezarpenak atalean. (Errore-kodea: <xliff:g id="CODE">%1$s</xliff:g>)"</item> + <item msgid="468830943567116703">"Wifi bidez deiak egiteko eta mezuak bidaltzeko, eskatu operadoreari zerbitzu hori gaitzeko. Ondoren, aktibatu Wifi bidezko deiak Ezarpenak atalean. (Errore-kodea: <xliff:g id="CODE">%1$s</xliff:g>)"</item> </string-array> <string-array name="wfcOperatorErrorNotificationMessages"> - <item msgid="4795145070505729156">"Arazo bat izan da Wi‑Fi bidezko deiak zure operadorearekin erregistratzean: <xliff:g id="CODE">%1$s</xliff:g>"</item> + <item msgid="4795145070505729156">"Arazo bat izan da wifi bidezko deiak zure operadorearekin erregistratzean: <xliff:g id="CODE">%1$s</xliff:g>"</item> </string-array> <!-- no translation found for wfcSpnFormat_spn (2982505428519096311) --> <skip /> - <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"<xliff:g id="SPN">%s</xliff:g> Wi-Fi bidezko deiak"</string> + <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"<xliff:g id="SPN">%s</xliff:g> operadorearen wifi bidezko deiak"</string> <string name="wfcSpnFormat_spn_wifi_calling_vo_hyphen" msgid="3836827895369365298">"<xliff:g id="SPN">%s</xliff:g> operadorearen wifi bidezko deiak"</string> <string name="wfcSpnFormat_wlan_call" msgid="4895315549916165700">"WLAN bidezko deia"</string> <string name="wfcSpnFormat_spn_wlan_call" msgid="255919245825481510">"<xliff:g id="SPN">%s</xliff:g> WLAN bidezko deia"</string> <string name="wfcSpnFormat_spn_wifi" msgid="7232899594327126970">"<xliff:g id="SPN">%s</xliff:g> wifia"</string> <string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="8383917598312067365">"Wi-Fi bidezko deiak | <xliff:g id="SPN">%s</xliff:g>"</string> <string name="wfcSpnFormat_spn_vowifi" msgid="6865214948822061486">"<xliff:g id="SPN">%s</xliff:g> VoWifi"</string> - <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Wi-Fi bidezko deiak"</string> + <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Wifi bidezko deiak"</string> <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> @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wifi-sarea soilik"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> operadorearen deietarako ordezko aukera"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ez da desbideratu"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> zenbakira <xliff:g id="TIME_DELAY">{2}</xliff:g> segundotan"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sentsorea aldi baterako desgaitu da."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> hatza"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Aurrera egiteko, erabili hatz-marka"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Erabili lasterbidea"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Koloreen alderantzikatzea"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Koloreen zuzenketa"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Murriztu distira"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu egin da."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu egin da."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> erabiltzeko, eduki sakatuta bi bolumen-botoiak hiru segundoz"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizatu"</string> <string name="close_button_text" msgid="10603510034455258">"Itxi"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Erantzun"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Baztertu"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Amaitu deia"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Jasotako deia"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Deia abian da"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Jasotako dei bat bistaratzen"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> hautatuta</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 6a0e45446341..75081e5e5787 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر بهطور موقت غیرفعال است."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"برای ادامه، از اثر انگشتتان استفاده کنید"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"نماد اثر انگشت"</string> @@ -1440,7 +1441,7 @@ <string name="notification_listener_binding_label" msgid="2702165274471499713">"شنونده اعلان"</string> <string name="vr_listener_binding_label" msgid="8013112996671206429">"شنونده VR"</string> <string name="condition_provider_service_binding_label" msgid="8490641013951857673">"ارائهدهنده وضعیت"</string> - <string name="notification_ranker_binding_label" msgid="432708245635563763">"سرویس رتبهبندی اعلان"</string> + <string name="notification_ranker_binding_label" msgid="432708245635563763">"سرویس ردهبندی اعلان"</string> <string name="vpn_title" msgid="5906991595291514182">"VPN فعال شد"</string> <string name="vpn_title_long" msgid="6834144390504619998">"VPN را <xliff:g id="APP">%s</xliff:g> فعال کرده است"</string> <string name="vpn_text" msgid="2275388920267251078">"برای مدیریت شبکه ضربه بزنید."</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"استفاده از میانبر"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"وارونگی رنگ"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"تصحیح رنگ"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"کاهش روشنایی"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> روشن شد."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"کلیدهای میزان صدا پایین نگه داشته شد. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> خاموش شد."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"برای استفاده از <xliff:g id="SERVICE_NAME">%1$s</xliff:g>، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"بزرگ کردن"</string> <string name="close_button_text" msgid="10603510034455258">"بستن"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"پاسخ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"رد کردن"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"قطع تماس"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"تماس ورودی"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"تماس درحال انجام"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"درحال غربال کردن تماس ورودی"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 8e5d9b44759a..42c220dfcf92 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tunnistin poistettu väliaikaisesti käytöstä."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Jatka sormenjäljen avulla"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sormenjälkikuvake"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Käytä pikanäppäintä"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Käänteiset värit"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Värinkorjaus"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Vähennä kirkkautta"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin päälle."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Äänenvoimakkuuspainikkeita painettiin pitkään. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> laitettiin pois päältä."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Voit käyttää palvelua <xliff:g id="SERVICE_NAME">%1$s</xliff:g> painamalla molempia äänenvoimakkuuspainikkeita kolmen sekunnin ajan"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Suurenna"</string> <string name="close_button_text" msgid="10603510034455258">"Sulje"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Vastaa"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Hylkää"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Lopeta puhelu"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Saapuva puhelu"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Käynnissä oleva puhelu"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Seulotaan saapuvaa puhelua"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valittu</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> valittu</item> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 849f9594729f..b4a22f46e4fa 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi seulement"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Méthode d\'appel secondaire avec <xliff:g id="SPN">%s</xliff:g>"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Le capteur a été désactivé temporairement."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilisez votre empreinte digitale pour continuer"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utiliser le raccourci"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Réduire la luminosité"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume maintenues enfoncées. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume maintenues enfoncées. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Maintenez enfoncées les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Agrandir"</string> <string name="close_button_text" msgid="10603510034455258">"Fermer"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g> : <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Répondre"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Refuser"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Raccrocher"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Appel entrant"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Appel en cours"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrer un appel entrant"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 60138c47d40e..8133f97dd0c1 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi uniquement"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Appels de secours via <xliff:g id="SPN">%s</xliff:g>"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Capteur temporairement désactivé."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilisez votre empreinte digitale pour continuer"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utiliser le raccourci"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Réduire la luminosité"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Appuyez de manière prolongée sur les deux touches de volume pendant trois secondes pour utiliser <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Agrandir"</string> <string name="close_button_text" msgid="10603510034455258">"Fermer"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g> : <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Répondre"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Refuser"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Raccrocher"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Appel entrant"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Appel en cours"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrer un appel entrant"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> élément sélectionné</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index eadac9edad74..526c74607fd4 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Desactivouse o sensor temporalmente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utiliza a túa impresión dixital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona de impresión dixital"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atallo"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversión de cor"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Corrección de cor"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reducir brillo"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume premidas. Activouse o servizo <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Desactivouse <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Mantén premidas as teclas do volume durante tres segudos para usar <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizar"</string> <string name="close_button_text" msgid="10603510034455258">"Pechar"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Resposta"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Rexeitar"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Colgar"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Chamada entrante"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chamada en curso"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando chamada entrante"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">Seleccionáronse <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="one">Seleccionouse <xliff:g id="COUNT_0">%1$d</xliff:g></item> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 86416bce3f48..e0e20af38496 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"ફક્ત વાઇ-ફાઇ"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> બૅકઅપ કૉલિંગ"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ફોરવર્ડ કર્યો નથી"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="TIME_DELAY">{2}</xliff:g> સેકન્ડ પછી <xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"આંગળી <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ચાલુ રાખવા માટે તમારી ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ફિંગરપ્રિન્ટ આયકન"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"શૉર્ટકટનો ઉપયોગ કરો"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"વિપરીત રંગમાં બદલવું"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"રંગ સુધારણા"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"બ્રાઇટનેસ ઘટાડો"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ચાલુ કરી."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"વૉલ્યૂમ કી દબાવી રાખો. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> બંધ કરી."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>નો ઉપયોગ કરવા માટે બન્ને વૉલ્યૂમ કીને ત્રણ સેકન્ડ સુધી દબાવી રાખો"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"મહત્તમ કરો"</string> <string name="close_button_text" msgid="10603510034455258">"બંધ કરો"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"જવાબ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"નકારો"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"સમાપ્ત કરો"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ઇનકમિંગ કૉલ"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"ચાલુ કૉલ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ઇનકમિંગ કૉલનું સ્ક્રીનિંગ થાય છે"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> પસંદ કરી</item> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 5f0a8f89b926..df97a1259fd8 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -303,7 +303,7 @@ <string name="managed_profile_label" msgid="7316778766973512382">"प्रोफ़ाइल बदलकर वर्क प्रोफ़ाइल पर जाएं"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"संपर्क"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"अपने संपर्कों को ऐक्सेस करने की"</string> - <string name="permgrouplab_location" msgid="1858277002233964394">"जगह"</string> + <string name="permgrouplab_location" msgid="1858277002233964394">"जगह की जानकारी"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"इस डिवाइस की जगह तक पहुंचने दें"</string> <string name="permgrouplab_calendar" msgid="6426860926123033230">"कैलेंडर"</string> <string name="permgroupdesc_calendar" msgid="6762751063361489379">"अपने कैलेंडर को ऐक्सेस करने"</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"फ़िंगरप्रिंट <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"जारी रखने के लिए फ़िंगरप्रिंट का इस्तेमाल करें"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फ़िंगरप्रिंट आइकॉन"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"शॉर्टकट का उपयोग करें"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"रंग बदलने की सुविधा"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"रंग में सुधार करने की सुविधा"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"स्क्रीन की चमक कम करें"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू कर दिया गया."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद कर दिया गया."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> इस्तेमाल करने के लिए आवाज़ वाले दोनों बटन तीन सेकंड तक दबाकर रखें"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"बड़ा करें"</string> <string name="close_button_text" msgid="10603510034455258">"बंद करें"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"जवाब दें"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"अस्वीकार करें"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"कॉल काटें"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"आने वाला (इनकमिंग) कॉल"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"जारी कॉल"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"इनकमिंग कॉल को स्क्रीन किया जा रहा है"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index e1ae1e24e0a1..fdadb5e170e4 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -582,6 +582,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Nastavite pomoću otiska prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string> @@ -1686,6 +1687,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Upotrijebi prečac"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija boja"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcija boje"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Smanjenje svjetline"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Držali ste tipke za glasnoću. Uključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Držali ste tipke za glasnoću. Isključila se usluga <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pritisnite i zadržite tipke za glasnoću na tri sekunde da biste koristili uslugu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1911,6 +1913,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimiziraj"</string> <string name="close_button_text" msgid="10603510034455258">"Zatvori"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Odgovori"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Odbij"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Prekini"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Dolazni poziv"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Poziv u tijeku"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtriranje dolaznog poziva"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> odabrana</item> <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> odabrane</item> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 3c04bec04151..dce975cf0080 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Az érzékelő átmenetileg le van tiltva."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"A folytatáshoz használja ujjlenyomatát"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ujjlenyomat ikon"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Billentyűparancs használata"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Színek invertálása"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Színkorrekció"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Fényerő csökkentése"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> bekapcsolva."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Nyomva tartotta a hangerőgombokat. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kikapcsolva."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"A(z) <xliff:g id="SERVICE_NAME">%1$s</xliff:g> használatához tartsa lenyomva három másodpercig a két hangerőgombot"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Teljes méret"</string> <string name="close_button_text" msgid="10603510034455258">"Bezárás"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Fogadás"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Elutasítás"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Befejezés"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Bejövő hívás"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Hívás folyamatban"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Bejövő hívás szűrése"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> kiválasztva</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kiválasztva</item> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index bdd238757bfb..ca4e9b8be535 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Տվիչը ժամանակավորապես անջատված է:"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Շարունակելու համար անհրաժեշտ է ձեր մատնահետքը"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Մատնահետքի պատկերակ"</string> @@ -1438,7 +1439,7 @@ <string name="wallpaper_binding_label" msgid="1197440498000786738">"Պաստառ"</string> <string name="chooser_wallpaper" msgid="3082405680079923708">"Փոխել պաստառը"</string> <string name="notification_listener_binding_label" msgid="2702165274471499713">"Ծանուցման ունկնդիր"</string> - <string name="vr_listener_binding_label" msgid="8013112996671206429">"VR ունկնդրիչ"</string> + <string name="vr_listener_binding_label" msgid="8013112996671206429">"VR ունկնիր"</string> <string name="condition_provider_service_binding_label" msgid="8490641013951857673">"Պայմանների մատակարար"</string> <string name="notification_ranker_binding_label" msgid="432708245635563763">"Ծանուցումների դասակարգման ծառայություն"</string> <string name="vpn_title" msgid="5906991595291514182">"VPN-ը ակտիվացված է"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Օգտագործել դյուրանցումը"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Գունաշրջում"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Գունաշտկում"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Նվազեցնել պայծառությունը"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունը միացավ։"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ձայնի կարգավորման կոճակները սեղմվեցին։ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ծառայությունն անջատվեց։"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"«<xliff:g id="SERVICE_NAME">%1$s</xliff:g>» ծառայությունն օգտագործելու համար սեղմեք և 3 վայրկյան պահեք ձայնի ուժգնության երկու կոճակները"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Մեծացնել"</string> <string name="close_button_text" msgid="10603510034455258">"Փակել"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Պատասխանել"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Մերժել"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Ավարտել"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Մուտքային զանգ"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Ընթացիկ զանգ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Մուտքային զանգի զտում"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index c84bc1318caf..e68812db464f 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor dinonaktifkan untuk sementara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gunakan sidik jari untuk melanjutkan"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon sidik jari"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversi Warna"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Koreksi Warna"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Kurangi Kecerahan"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> diaktifkan."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dinonaktifkan."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua tombol volume selama tiga detik untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimalkan"</string> <string name="close_button_text" msgid="10603510034455258">"Tutup"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Jawab"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Tolak"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Tutup"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Panggilan masuk"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Panggilan sedang berlangsung"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Menyaring panggilan masuk"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 84611a2d44a9..2076363a19fd 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Slökkt tímabundið á skynjara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Notaðu fingrafarið þitt til að halda áfram"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingrafaratákn"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Nota flýtileið"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Umsnúningur lita"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Litaleiðrétting"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Draga úr birtu"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Hljóðstyrkstökkum haldið inni. Kveikt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Hljóðstyrkstökkum haldið inni. Slökkt á <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Haltu báðum hljóðstyrkstökkunum inni í þrjár sekúndur til að nota <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Stækka"</string> <string name="close_button_text" msgid="10603510034455258">"Loka"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Svara"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Hafna"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Leggja á"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Símtal berst"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Símtal í gangi"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Síar símtal sem berst"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> valið</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valin</item> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 2fcc273880f7..34ee5dc4a664 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Solo Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Chiamate di backup <xliff:g id="SPN">%s</xliff:g>"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> dopo <xliff:g id="TIME_DELAY">{2}</xliff:g> secondi"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensore temporaneamente disattivato."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilizza la tua impronta per continuare"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona dell\'impronta"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usa scorciatoia"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversione dei colori"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Correzione del colore"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Riduci la luminosità"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> attivato."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tieni premuti i tasti del volume. Servizio <xliff:g id="SERVICE_NAME">%1$s</xliff:g> disattivato."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tieni premuti entrambi i tasti del volume per tre secondi per utilizzare <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Ingrandisci"</string> <string name="close_button_text" msgid="10603510034455258">"Chiudi"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Rispondi"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Rifiuta"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Riaggancia"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Chiamata in arrivo"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chiamata in corso"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Applicazione filtro a chiamata in arrivo"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> file selezionati</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> file selezionato</item> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index f104d442d154..9595da6f3871 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -585,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר זה אין חיישן טביעות אצבע."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"החיישן מושבת באופן זמני."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"יש להשתמש בטביעת האצבע כדי להמשיך"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"סמל טביעת אצבע"</string> @@ -1708,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"השתמש בקיצור הדרך"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"היפוך צבעים"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"תיקון צבעים"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"הפחתה של עוצמת הבהירות"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הופעל."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"לחצני עוצמת הקול נלחצו בלחיצה ארוכה. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> הושבת."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"יש ללחוץ לחיצה ארוכה על שני לחצני עוצמת הקול למשך שלוש שניות כדי להשתמש בשירות <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1942,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"הגדל"</string> <string name="close_button_text" msgid="10603510034455258">"סגירה"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"תשובה"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"דחייה"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ניתוק"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"שיחה נכנסת"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"שיחה פעילה"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"סינון שיחה נכנסת"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="two">בחרת <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="many">בחרת <xliff:g id="COUNT_1">%1$d</xliff:g></item> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 69822ac67fb5..dd3667edd022 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -203,7 +203,7 @@ <string name="sensor_notification_service" msgid="7474531979178682676">"センサー通知サービス"</string> <string name="twilight_service" msgid="8964898045693187224">"トワイライト サービス"</string> <string name="offline_location_time_zone_detection_service_attribution" msgid="303754195048744816">"Time Zone Detector(未接続)"</string> - <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS Time Update Service"</string> + <string name="gnss_time_update_service" msgid="9039489496037616095">"GNSS 時間アップデートサービス"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string> <string name="factory_reset_message" msgid="2657049595153992213">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"センサーが一時的に無効になっています。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"指紋 <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"続行するには指紋認証を使用してください"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋アイコン"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ショートカットを使用"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"色反転"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"色補正"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"明るさを下げる"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が ON になりました。"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"音量ボタンを長押ししました。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> が OFF になりました。"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> を使用するには、音量大と音量小の両方のボタンを 3 秒間長押ししてください"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"最大化"</string> <string name="close_button_text" msgid="10603510034455258">"閉じる"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"応答"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"拒否"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"通話終了"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"着信"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"通話中"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"着信をスクリーニング中"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>件選択済み</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>件選択済み</item> @@ -2060,9 +2068,9 @@ <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"電源ダイアログ"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string> <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string> - <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"画面上のユーザー補助のショートカット"</string> - <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"画面上のユーザー補助のショートカットの選択メニュー"</string> - <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ユーザー補助のショートカット"</string> + <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"画面上のユーザー補助機能のショートカット"</string> + <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"画面上のユーザー補助機能のショートカットの選択メニュー"</string> + <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"ユーザー補助機能のショートカット"</string> <string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string> <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 6a7d563c2dc7..b8454983ed2f 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"სენსორი დროებით გათიშულია."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"თითი <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"თითის ანაბეჭდის ხატულა"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"მალსახმობის გამოყენება"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"ფერთა ინვერსია"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"ფერთა კორექცია"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"სიკაშკაშის შემცირება"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ჩართულია."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> გამორთულია."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> რომ გამოიყენოთ, დააჭირეთ ხმის ორივე ღილაკზე 3 წამის განმავლობაში"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"მაქსიმალური ზომა"</string> <string name="close_button_text" msgid="10603510034455258">"დახურვა"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"პასუხი"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"უარყოფა"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"გათიშვა"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"შემომავალი ზარი"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"მიმდინარე ზარი"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"შემომავალი ზარების გაცხრილვა"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> შერჩეული</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> შერჩეული</item> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index aec2312c0a21..5cb4f755578f 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Тек Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> Қосалқы қоңырау шалу"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Басқа нөмірге бағытталмады"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> секундтан кейін"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик уақытша өшірулі."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> саусағы"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Жалғастыру үшін саусақ ізін пайдаланыңыз."</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Саусақ ізі белгішесі"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Төте жолды пайдалану"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Түстер инверсиясы"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Түсті түзету"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Жарықтығын азайту"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Пайдаланушы дыбыс деңгейі пернелерін басып ұстап тұрды. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> қосулы."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дыбыс деңгейі пернелерін басып тұрған соң, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өшірілді."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> қызметін пайдалану үшін дыбыс деңгейін реттейтін екі түймені де 3 секунд басып тұрыңыз"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Жазу"</string> <string name="close_button_text" msgid="10603510034455258">"Жабу"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Жауап"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Қабылдамау"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Тұтқаны қою"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Кіріс қоңырау"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Қоңырау"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Келген қоңырауды сүзу"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> таңдалды</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> таңдалды</item> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index d1400b9d17ff..d0093115924e 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះមិនមានឧបករណ៍ចាប់ស្នាមម្រាមដៃទេ។"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ម្រាមដៃ <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ប្រើស្នាមម្រាមដៃរបស់អ្នក ដើម្បីបន្ត"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"រូបស្នាមម្រាមដៃ"</string> @@ -1108,7 +1109,7 @@ <string name="cut" msgid="2561199725874745819">"កាត់"</string> <string name="copy" msgid="5472512047143665218">"ចម្លង"</string> <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"មិនអាចចម្លងទៅអង្គចងចាំទេ"</string> - <string name="paste" msgid="461843306215520225">"បិទភ្ជាប់"</string> + <string name="paste" msgid="461843306215520225">"ដាក់ចូល"</string> <string name="paste_as_plain_text" msgid="7664800665823182587">"បិទភ្ជាប់ជាអត្ថបទធម្មតា"</string> <string name="replace" msgid="7842675434546657444">"ជំនួស..."</string> <string name="delete" msgid="1514113991712129054">"លុប"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ប្រើប្រាស់ផ្លូវកាត់"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"បញ្ច្រាសពណ៌"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"ការកែពណ៌"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"បន្ថយពន្លឺ"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបើក <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"បានសង្កត់គ្រាប់ចុចកម្រិតសំឡេងជាប់។ បានបិទ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>។"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ចុចគ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលបីវិនាទី ដើម្បីប្រើ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"ពង្រីក"</string> <string name="close_button_text" msgid="10603510034455258">"បិទ"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>៖ <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"ឆ្លើយ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"បដិសេធ"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ដាក់ចុះ"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ការហៅចូល"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"ការហៅដែលកំពុងដំណើរការ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"កំពុងពិនិត្យការហៅចូល"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">បានជ្រើស <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="one">បានជ្រើស <xliff:g id="COUNT_0">%1$d</xliff:g></item> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 32e3c4d98578..48684866ffdc 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ಫಿಂಗರ್ <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಐಕಾನ್"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ಶಾರ್ಟ್ಕಟ್ ಬಳಸಿ"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"ಬಣ್ಣ ವಿಲೋಮ"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ಪ್ರಖರತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದುಕೊಳ್ಳಿ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಲಾಗಿದೆ. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಲು ಎರಡೂ ಧ್ವನಿ ಕೀಗಳನ್ನು ಮೂರು ಸೆಕೆಂಡ್ಗಳ ಕಾಲ ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"ಹಿಗ್ಗಿಸು"</string> <string name="close_button_text" msgid="10603510034455258">"ಮುಚ್ಚು"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"ಉತ್ತರಿಸಿ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"ನಿರಾಕರಿಸಿ"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ಹ್ಯಾಂಗ್ ಅಪ್"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ಒಳಬರುವ ಕರೆ"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಕರೆ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ಒಳಬರುವ ಕರೆಯನ್ನು ಸ್ಕ್ರೀನ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 34074312e70d..6149e4b048ef 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"센서가 일시적으로 사용 중지되었습니다."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"계속하려면 지문을 사용하세요."</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"지문 아이콘"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"단축키 사용"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"색상 반전"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"색상 보정"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"밝기 낮추기"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 설정되었습니다."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"볼륨 키를 길게 눌렀습니다. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>이(가) 사용 중지되었습니다."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 서비스를 사용하려면 두 볼륨 키를 3초 동안 길게 누르세요"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"최대화"</string> <string name="close_button_text" msgid="10603510034455258">"닫기"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"답변"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"거절"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"전화 끊기"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"수신 전화"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"진행 중인 통화"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"수신 전화 검사 중"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>개 선택됨</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 선택됨</item> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 9a84d0a985e6..e2f539728f25 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -298,7 +298,7 @@ <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"Батареянын кубаты жана трафиктин көлөмү жөнүндө билүү үчүн таптап коюңуз"</string> <string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string> <string name="safeMode" msgid="8974401416068943888">"Коопсуз режим"</string> - <string name="android_system_label" msgid="5974767339591067210">"Android тутуму"</string> + <string name="android_system_label" msgid="5974767339591067210">"Android системасы"</string> <string name="user_owner_label" msgid="8628726904184471211">"Жеке профилге которулуу"</string> <string name="managed_profile_label" msgid="7316778766973512382">"Жумуш профилине которулуу"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"Байланыштар"</string> @@ -332,7 +332,7 @@ <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Көрүнүштү чоңойтуп кичирейтет"</string> <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Экрандагы сүрөттү тууралап жайгаштырып, өлчөмүн өзгөртөт."</string> <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Жаңсоолорду аткаруу"</string> - <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Таптап, серпип, чымчып жана башка жаңсоолорду аткара алат."</string> + <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Таптап, сүрүп, чымчып жана башка жаңсоолорду аткара алат."</string> <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Манжа изинин жаңсоолору"</string> <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Түзмөктөгү манжа изинин сенсорунда жасалган жаңсоолорду жаздырып алат."</string> <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Скриншот тартып алуу"</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сенсор убактылуу өчүрүлгөн."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-манжа"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Улантуу үчүн манжаңыздын изин колдонуңуз"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Манжа изинин сүрөтчөсү"</string> @@ -886,7 +887,7 @@ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Сиз телефонду бөгөттөн чыгарууга <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Телефон баштапкы абалына келтирилет."</string> <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> секунддан кийин кайталаңыз."</string> <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Сүрөт үлгүсүн унутуп калдыңызбы?"</string> - <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Каттоо эсеби менен кулпусун ачуу"</string> + <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Аккаунт менен кулпусун ачуу"</string> <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Өтө көп үлгү киргизүү аракети болду"</string> <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Бөгөттөн чыгарыш үчүн, Google эсебиңиз менен кириңиз."</string> <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Колдонуучунун аты (электрондук почта)"</string> @@ -1664,12 +1665,13 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Кыска жолду колдонуу"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Түстү инверсиялоо"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Түсүн тууралоо"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Экрандын жарыктыгын төмөндөтүү"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> күйгүзүлдү."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Үндү катуулатуу/акырындатуу баскычтары басылып, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> өчүрүлдү."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> кызматын колдонуу үчүн үнүн чоңойтуп/кичирейтүү баскычтарын үч секунд коё бербей басып туруңуз"</string> <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Атайын мүмкүнчүлүктөр баскычын таптаганыңызда иштей турган функцияны тандаңыз:"</string> - <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Атайын мүмкүнчүлүктөр жаңсоосу үчүн функцияны тандаңыз (эки манжаңыз менен экрандын ылдый жагынан өйдө карай сүрүңүз):"</string> - <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Атайын мүмкүнчүлүктөр жаңсоосу аркылуу иштетиле турган функцияны тандаңыз (үч манжаңыз менен экрандын ылдый жагынан өйдө карай сүрүңүз):"</string> + <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Атайын мүмкүнчүлүктөр жаңсоосу үчүн функцияны тандаңыз (эки манжаңыз менен экранды ылдыйдан өйдө сүрүңүз):"</string> + <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Атайын мүмкүнчүлүктөр жаңсоосу аркылуу иштетиле турган функцияны тандаңыз (үч манжаңыз менен экранды ылдыйдан өйдө сүрүңүз):"</string> <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Функцияларды которуштуруу үчүн, Атайын мүмкүнчүлүктөр баскычын басып, кармап туруңуз."</string> <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Функцияларды которуштуруу үчүн, эки манжаңыз менен өйдө сүрүп, кармап туруңуз."</string> <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Башка функцияга которулуу үчүн үч манжаңыз менен экранды өйдө сүрүп, кармап туруңуз."</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Чоңойтуу"</string> <string name="close_button_text" msgid="10603510034455258">"Жабуу"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Жооп берүү"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Четке кагуу"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Чалууну бүтүрүү"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Кирүүчү чалуу"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Учурдагы чалуу"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Кирүүчү чалууну иргөө"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> тандалды</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 9977f9fca122..c41c4111e87c 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi ເທົ່ານັ້ນ"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> ການໂທສຳຮອງ"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ບໍ່ຖືກສົ່ງຕໍ່"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> ຫຼັງຈາກ <xliff:g id="TIME_DELAY">{2}</xliff:g> ວິນາທີ"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ນີ້ວມື <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ໃຊ້ລາຍນີ້ວມືຂອງທ່ານເພື່ອສືບຕໍ່"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ໄອຄອນລາຍນິ້ວມື"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ໃຊ້ປຸ່ມລັດ"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"ການປີ້ນສີ"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"ການແກ້ໄຂຄ່າສີ"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ຫຼຸດຄວາມສະຫວ່າງ"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ເປີດໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ແລ້ວ."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ປິດ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ໄວ້ແລ້ວ."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"ກົດປຸ່ມສຽງທັງສອງພ້ອມກັນຄ້າງໄວ້ສາມວິນາທີເພື່ອໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"ຂະຫຍາຍອອກ"</string> <string name="close_button_text" msgid="10603510034455258">"ປິດ"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"ຮັບສາຍ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"ປະຕິເສດ"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ວາງສາຍ"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ສາຍໂທເຂົ້າ"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"ສາຍໂທອອກ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ກຳລັງກວດສອບສາຍໂທເຂົ້າ"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ຖືກເລືອກແລ້ວ</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ຖືກເລືອກແລ້ວ</item> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 5f72e07a6959..b9b2131341b4 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -585,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Jutiklis laikinai išjungtas."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Naudokite kontrolinį kodą, kad galėtumėte tęsti"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Piršto antspaudo piktograma"</string> @@ -1708,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Naudoti spartųjį klavišą"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Spalvų inversija"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Spalvų taisymas"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Šviesumo mažinimas"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ įjungta."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Laikomi garsumo klavišai. „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“ išjungta."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Jei norite naudoti „<xliff:g id="SERVICE_NAME">%1$s</xliff:g>“, paspauskite abu garsumo klavišus ir palaikykite tris sekundes"</string> @@ -1942,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Padidinti"</string> <string name="close_button_text" msgid="10603510034455258">"Uždaryti"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Atsakyti"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Atmesti"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Baigti pok."</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Gaunamasis skambutis"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Vykstantis skambutis"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Gaunamojo skambučio tikrinimas"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item> <item quantity="few">Pasir. <xliff:g id="COUNT_1">%1$d</xliff:g> elem.</item> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 37e417fa6a56..803574fe85b8 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -582,6 +582,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensors ir īslaicīgi atspējots."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Lai turpinātu, izmantojiet pirksta nospiedumu"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pirksta nospieduma ikona"</string> @@ -1686,6 +1687,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Izmantot saīsni"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Krāsu inversija"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Krāsu korekcija"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Spilgtuma samazināšana"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika ieslēgts."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Turējāt nospiestas skaļuma pogas. Pakalpojums <xliff:g id="SERVICE_NAME">%1$s</xliff:g> tika izslēgts."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Lai izmantotu pakalpojumu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, nospiediet abus skaļuma taustiņus un turiet tos trīs sekundes."</string> @@ -1911,6 +1913,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimizēt"</string> <string name="close_button_text" msgid="10603510034455258">"Aizvērt"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Atbildēt"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Noraidīt"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Pārtraukt"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Ienākošais zvans"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Pašreizējais zvans"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Ienākošā zvana filtrēšana"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="zero"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīts</item> diff --git a/core/res/res/values-mcc310-mnc950-si/strings.xml b/core/res/res/values-mcc310-mnc950-si/strings.xml new file mode 100644 index 000000000000..26fe4ac265a3 --- /dev/null +++ b/core/res/res/values-mcc310-mnc950-si/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr" msgid="615419724607901560">"SIM MM#2 ප්රතිපාදනය නොකරයි"</string> + <string name="mmcc_illegal_ms" msgid="7801541624846497489">"SIM MM#3 ඉඩ නොදේ"</string> + <string name="mmcc_illegal_me" msgid="7066936962628406316">"දුරකථනය MM#6 ඉඩ නොදේ"</string> +</resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 5666cc23f2be..dd48273acca0 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорот е привремено оневозможен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Користете го отпечатокот за да продолжите"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатоци"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Користи кратенка"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Инверзија на бои"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Корекција на бои"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Намалете ја осветленоста"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е вклучена."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ги задржавте копчињата за јачина на звук. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> е исклучена."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притиснете ги и задржете ги двете копчиња за јачина на звукот во траење од три секунди за да користите <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Зголеми"</string> <string name="close_button_text" msgid="10603510034455258">"Затвори"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Одговори"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Одбиј"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Спушти"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Дојдовен повик"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Тековен повик"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Проверка на дојдовен повик"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> е избрана</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> се избрани</item> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index e0d4b0179624..c2576fe92fb6 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"വൈഫൈ മാത്രം"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> ബാക്കപ്പ് കോളിംഗ്"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: കൈമാറിയില്ല"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> നിമിഷത്തിനുശേഷം <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"കൈവിരൽ <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"തുടരുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"കുറുക്കുവഴി ഉപയോഗിക്കുക"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"വർണ്ണ വിപര്യയം"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"നിറം ക്രമീകരിക്കൽ"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"തെളിച്ചം കുറയ്ക്കുക"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"വോളിയം കീകൾ പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓണാക്കി."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"വോളിയം കീകൾ അമർത്തിപ്പിടിച്ചു. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഓഫാക്കി."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ഉപയോഗിക്കാൻ, രണ്ട് വോളിയം കീകളും മൂന്ന് സെക്കൻഡ് അമർത്തിപ്പിടിക്കുക"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"വലുതാക്കുക"</string> <string name="close_button_text" msgid="10603510034455258">"അവസാനിപ്പിക്കുക"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"മറുപടി നൽകുക"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"നിരസിക്കുക"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"കോൾ നിർത്തുക"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ഇൻകമിംഗ് കോൾ"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"സജീവമായ കോൾ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ഇൻകമിംഗ് കോൾ സ്ക്രീൻ ചെയ്യൽ"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> എണ്ണം തിരഞ്ഞെടുത്തു</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> എണ്ണം തിരഞ്ഞെടുത്തു</item> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 891ac47191e1..786f722132fc 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -325,7 +325,7 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"таны биеийн байдлын талаарх мэдрэгч бүхий өгөгдөлд нэвтрэх"</string> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Цонхны агуулгыг авах"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Таны харилцан үйлчлэх цонхны контентоос шалгах."</string> - <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Хүрч танихыг асаах"</string> + <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Хүрэлтээр сонсохыг асаах"</string> <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Товшсон зүйлсийг чангаар хэлэх ба дэлгэцийг дохио ашиглан таних боломжтой."</string> <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Бичсэн текстээ ажиглах"</string> <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Кредит картын дугаар болон нууц үг зэрэг хувийн датаг агуулж байна."</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Хурууны хээ <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Үргэлжлүүлэхийн тулд хурууны хээгээ ашиглаарай"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Хурууны хээний дүрс"</string> @@ -1002,9 +1003,9 @@ <string name="searchview_description_clear" msgid="1989371719192982900">"Асуулгыг цэвэрлэх"</string> <string name="searchview_description_submit" msgid="6771060386117334686">"Асуулгыг илгээх"</string> <string name="searchview_description_voice" msgid="42360159504884679">"Дуут хайлт"</string> - <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Хүрч хайх функцийг идэвхтэй болгох уу?"</string> - <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> нь Хүрч танихыг идэвхжүүлэхийг шаардаж байна. Хүрч таних идэвхжсэн үед та хуруун доороо юу байгааг сонсох, тайлбарыг харах боломжтой ба таблеттайгаа дохиогоор харилцах боломжтой."</string> - <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> нь Хүрч танихыг идэвхжүүлэхийг шаардаж байна. Хүрч таних идэвхжсэн тохиолдолд та хуруун доороо юу байгааг сонсох, тайлбарыг харах боломжтой ба утастайгаа дохиогоор харилцах боломжтой."</string> + <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Хүрэлтээр сонсохыг идэвхжүүлэх үү?"</string> + <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> нь Хүрэлтээр сонсохыг идэвхжүүлэхийг шаардаж байна. Хүрэлтээр сонсох идэвхжсэн үед та хуруун доороо юу байгааг сонсох, тайлбарыг харах боломжтой ба таблеттайгаа дохиогоор харилцах боломжтой."</string> + <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> нь Хүрэлтээр сонсохыг идэвхжүүлэхийг шаардаж байна. Хүрэлтээр сонсох идэвхжсэн тохиолдолд та хуруун доороо юу байгааг сонсох, тайлбарыг харах боломжтой ба утастайгаа дохиогоор харилцах боломжтой."</string> <string name="oneMonthDurationPast" msgid="4538030857114635777">"1 сарын өмнө"</string> <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"1 сарын өмнө"</string> <plurals name="last_num_days" formatted="false" msgid="687443109145393632"> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Товчлол ашиглах"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Өнгө хувиргалт"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Өнгөний засвар"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Гэрэлтүүлгийг багасгах"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г асаалаа."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Дууны түвшний түлхүүрийг удаан дарсан. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г унтраалаа."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>-г ашиглахын тулд дууны түвшнийг ихэсгэх, багасгах түлхүүрийг 3 секундийн турш зэрэг дарна уу"</string> @@ -1871,7 +1873,7 @@ <string name="notification_alerted_content_description" msgid="6139691253611265992">"Мэдэгдсэн"</string> <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Дэлгэх"</string> <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Буулгах"</string> - <string name="expand_action_accessibility" msgid="1947657036871746627">"унтраах/асаах өргөтгөл"</string> + <string name="expand_action_accessibility" msgid="1947657036871746627">"асаах/унтраах өргөтгөл"</string> <string name="usb_midi_peripheral_name" msgid="490523464968655741">"Андройд USB Peripheral Port"</string> <string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"Android"</string> <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"USB Peripheral Port"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Томруулах"</string> <string name="close_button_text" msgid="10603510034455258">"Хаах"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Хариулах"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Татгалзах"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Таслах"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Ирсэн дуудлага"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Дуудлага хийгдэж байна"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Ирсэн дуудлагыг харуулж байна"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> сонгосон</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> сонгосон</item> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index d57c4c1d0d05..c1b8088a870e 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"केवळ वाय-फाय"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> बॅकअप कॉलिंग"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: फॉरवर्ड केला नाही"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकंदांनंतर <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"या डिव्हाइसमध्ये फिंगरप्रिंट सेन्सर नाही."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेन्सर तात्पुरता बंद केला आहे."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> बोट"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"पुढे सुरू ठेवण्यासाठी तुमची फिंगरप्रिंट वापरा"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिंट आयकन"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"शॉर्टकट वापरा"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"रंगांची उलटापालट"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"रंग सुधारणा"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ब्राइटनेस कमी करा"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> सुरू केला आहे."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"धरून ठेवलेल्या व्हॉल्यूम की. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> बंद केले आहे."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> वापरण्यासाठी दोन्ही व्हॉल्युम की तीन सेकंद दाबा आणि धरून ठेवा"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"मोठे करा"</string> <string name="close_button_text" msgid="10603510034455258">"बंद करा"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"उत्तर द्या"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"नकार द्या"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"कॉल बंद करा"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"इनकमिंग कॉल"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"सुरू असलेला कॉल"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"इनकमिंग कॉल स्क्रीन करत आहे"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> निवडले</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> निवडला</item> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index ec0aa5d6fae6..5e26682fd664 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -325,7 +325,7 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"akses data penderia tentang tanda vital anda"</string> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Dapatkan kembali kandungan tetingkap"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Periksa kandungan tetingkap yang berinteraksi dengan anda."</string> - <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Hidupkan Jelajah melalui Sentuhan"</string> + <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Hidupkan Teroka melalui Sentuhan"</string> <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Item yang diketik akan dituturkan dengan lantang dan skrin boleh dijelajah menggunakan gerak isyarat."</string> <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Perhatikan teks yang anda taip"</string> <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Termasuk data peribadi seperti nombor kad kredit dan kata laluan."</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Penderia dilumpuhkan sementara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gunakan cap jari anda untuk teruskan"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon cap jari"</string> @@ -1002,9 +1003,9 @@ <string name="searchview_description_clear" msgid="1989371719192982900">"Pertanyaan jelas"</string> <string name="searchview_description_submit" msgid="6771060386117334686">"Serah pertanyaan"</string> <string name="searchview_description_voice" msgid="42360159504884679">"Carian suara"</string> - <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Dayakan Jelajah melalui Sentuhan?"</string> - <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Jelajah melalui Sentuhan. Apabila Jelajah melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan tablet."</string> - <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Jelajah melalui Sentuhan. Apabila Jelajah melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan telefon."</string> + <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Dayakan Teroka melalui Sentuhan?"</string> + <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Teroka melalui Sentuhan. Apabila Teroka melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa-apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan tablet."</string> + <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ingin mendayakan Teroka melalui Sentuhan. Apabila Teroka melalui Sentuhan didayakan, anda boleh mendengar atau melihat penerangan tentang apa-apa di bawah jari anda atau melakukan gerak isyarat untuk berinteraksi dengan telefon."</string> <string name="oneMonthDurationPast" msgid="4538030857114635777">"1 bulan yang lalu"</string> <string name="beforeOneMonthDurationPast" msgid="8315149541372065392">"Sebelum 1 bulan yang lalu"</string> <plurals name="last_num_days" formatted="false" msgid="687443109145393632"> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Penyongsangan Warna"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Pembetulan Warna"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Kurangkan Kecerahan"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dihidupkan."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dimatikan."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tekan dan tahan kedua-dua kekunci kelantangan selama tiga saat untuk menggunakan <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimumkan"</string> <string name="close_button_text" msgid="10603510034455258">"Tutup"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Jawapan"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Tolak"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Tamatkan Panggilan"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Panggilan masuk"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Panggilan sedang berlangsung"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Menyaring panggilan masuk"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 7b4a430fc1bb..aff554916517 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ရှေ့ဆက်ရန် သင့်လက်ဗွေကို သုံးပါ"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"လက်ဗွေ သင်္ကေတ"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ဖြတ်လမ်းလင့်ခ်ကို သုံးရန်"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"အရောင် ပြောင်းပြန်လှန်ခြင်း"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"အရောင်ပြင်ဆင်ခြင်း"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"တောက်ပမှုကို လျှော့ခြင်း"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ဖွင့်လိုက်သည်။"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ပိတ်လိုက်သည်။"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ကို သုံးရန် အသံအတိုးအလျှော့ ခလုတ်နှစ်ခုလုံးကို သုံးစက္ကန့်ကြာ ဖိထားပါ"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"အများဆုံး လုပ်ပေးရန်"</string> <string name="close_button_text" msgid="10603510034455258">"ပိတ်ရန်"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>− <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"ဖုန်းကိုင်ရန်"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"ငြင်းပယ်ရန်"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ဖုန်းချရန်"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"အဝင်ခေါ်ဆိုမှု"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"လက်ရှိခေါ်ဆိုမှု"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"အဝင်ခေါ်ဆိုမှုကို စစ်ဆေးနေသည်"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ရွေးချယ်ပြီးပါပြီ</item> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 496818426714..21ca11701f08 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidig slått av."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Bruk fingeravtrykket ditt for å fortsette"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeravtrykk"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Bruk snarveien"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Fargeinvertering"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Fargekorrigering"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduser lysstyrken"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått på."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått av."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Trykk og hold inne begge volumtastene i tre sekunder for å bruke <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimer"</string> <string name="close_button_text" msgid="10603510034455258">"Lukk"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g><xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Svar"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Avvis"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Legg på"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Innkommende anrop"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Pågående samtale"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrerer et innkommende anrop"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> er valgt</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 541ace80518c..09b97652bb6c 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi मात्र"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> ब्याकअप कलिङ"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अगाडि पठाइएको छैन"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> पछि <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकेन्ड"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो यन्त्रमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"केही समयका लागि सेन्सर असक्षम पारियो।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"औंला <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"जारी राख्न आफ्नो फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिन्ट आइकन"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"सर्टकट प्रयोग गर्नुहोस्"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"रङ्ग उल्टाउने सुविधा"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"रङ्ग सच्याउने सुविधा"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"स्क्रिनको चमक घटाउनुहोस्"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन भयो।"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"तपाईंले भोल्युम बटनहरू थिचिराख्नुभयो। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अफ भयो।"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> प्रयोग गर्न दुवै भोल्युम कुञ्जीहरूलाई तीन सेकेन्डसम्म थिचिराख्नुहोस्"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"ठुलो बनाउनुहोस्"</string> <string name="close_button_text" msgid="10603510034455258">"बन्द गर्नुहोस्"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"कलको जवाफ दिनु…"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"अस्वीकार गर्नुहोस्"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"फोन राख्नुहोस्"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"आगमन कल"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"भइरहेको कल"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"आगमन कल जाँचिँदै छ"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयन गरियो</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> चयन गरियो</item> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 7f23cbbbb6dd..6d1b8e77ed9b 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -515,9 +515,9 @@ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Hiermee kan de app pakketten ontvangen die via multicastadressen naar alle apparaten in een wifi-netwerk worden verzonden, niet alleen naar je Android TV-apparaat. Het stroomgebruik ligt hierbij hoger dan in de niet-multicastmodus."</string> <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Hiermee kan de app pakketten ontvangen die via multicastadressen naar alle apparaten in een wifi-netwerk worden verzonden, niet alleen naar je telefoon. Het stroomgebruik ligt hierbij hoger dan in de niet-multicastmodus."</string> <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"Bluetooth-instellingen openen"</string> - <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Hiermee kan de app de lokale bluetooth-tablet configureren en externe apparaten zoeken en koppelen."</string> - <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Hiermee kan de app Bluetooth op je Android TV-apparaat configureren en externe apparaten zoeken en koppelen."</string> - <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Hiermee kan de app de lokale bluetooth-telefoon configureren en externe apparaten zoeken en koppelen."</string> + <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Hiermee kan de app de lokale bluetooth-tablet instellen en externe apparaten zoeken en koppelen."</string> + <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Hiermee kan de app Bluetooth op je Android TV-apparaat isntellen en externe apparaten zoeken en koppelen."</string> + <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Hiermee kan de app de lokale bluetooth-telefoon instellen en externe apparaten zoeken en koppelen."</string> <string name="permlab_accessWimaxState" msgid="7029563339012437434">"WiMAX-verbinding maken en verbreken"</string> <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Hiermee kan de app bepalen of WiMAX is ingeschakeld en informatie bekijken over alle WiMAX-netwerken waarmee verbinding is gemaakt."</string> <string name="permlab_changeWimaxState" msgid="6223305780806267462">"WiMAX-status wijzigen"</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor tijdelijk uitgeschakeld."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gebruik je vingerafdruk om door te gaan."</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string> @@ -1346,7 +1347,7 @@ <string name="select_input_method" msgid="3971267998568587025">"Invoermethode selecteren"</string> <string name="show_ime" msgid="6406112007347443383">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string> <string name="hardware" msgid="1800597768237606953">"Virtueel toetsenbord tonen"</string> - <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"Fysiek toetsenbord configureren"</string> + <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"Fysiek toetsenbord instellen"</string> <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tik om een taal en indeling te selecteren"</string> <string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> @@ -1369,7 +1370,7 @@ <string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"Je moet het apparaat misschien opnieuw formatteren. Tik om het uit te werpen."</string> <string name="ext_media_unsupported_notification_title" msgid="4358280700537030333">"<xliff:g id="NAME">%s</xliff:g> niet ondersteund"</string> <string name="ext_media_unsupported_notification_title" product="automotive" msgid="6004193172658722381">"<xliff:g id="NAME">%s</xliff:g> werkt niet"</string> - <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"Dit apparaat biedt geen ondersteuning voor deze <xliff:g id="NAME">%s</xliff:g>. Tik om te configureren in een ondersteunde indeling."</string> + <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"Dit apparaat biedt geen ondersteuning voor deze <xliff:g id="NAME">%s</xliff:g>. Tik om in te stellen in een ondersteunde indeling."</string> <string name="ext_media_unsupported_notification_message" product="tv" msgid="7744945987775645685">"Dit apparaat biedt geen ondersteuning voor deze <xliff:g id="NAME">%s</xliff:g>. Selecteer om in te stellen in een ondersteunde indeling."</string> <string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"Je moet het apparaat misschien opnieuw formatteren"</string> <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> is onverwacht verwijderd"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sneltoets gebruiken"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Kleurinversie"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurcorrectie"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Helderheid verlagen"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> is ingeschakeld."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximaliseren"</string> <string name="close_button_text" msgid="10603510034455258">"Sluiten"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Beantwoorden"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Weigeren"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Ophangen"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Inkomend gesprek"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Actief gesprek"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Een inkomend gesprek screenen"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> geselecteerd</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> geselecteerd</item> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index f02d1573b7b2..dc28d60ca05e 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"କେବଳ ୱାଇ-ଫାଇ"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> ବ୍ୟାକଅପ୍ କଲିଂ"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ଫରୱାର୍ଡ କରାଯାଇନାହିଁ"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ସେକେଣ୍ଡ ପରେ"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍ରେ ଟିପଚିହ୍ନ ସେନ୍ସର୍ ନାହିଁ।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ଆଙ୍ଗୁଠି <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ଶର୍ଟକଟ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"ରଙ୍ଗ ବଦଳାଇବାର ସୁବିଧା"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"ରଙ୍ଗ ସଂଶୋଧନ"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ଉଜ୍ଜ୍ୱଳତା କମାନ୍ତୁ"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ଚାଲୁ ହୋଇଛି।"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ଭଲ୍ୟୁମ୍ କୀ\'ଗୁଡ଼ିକୁ ଧରି ରଖାଯାଇଛି। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବନ୍ଦ ହୋଇଛି।"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବାକୁ ତିନି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ ଦବାଇ ଧରି ରଖନ୍ତୁ"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"ବଡ଼ କରନ୍ତୁ"</string> <string name="close_button_text" msgid="10603510034455258">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"ଉତ୍ତର ଦିଅନ୍ତୁ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"ଅଗ୍ରାହ୍ୟ କର"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ସମାପ୍ତ କରନ୍ତୁ"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ଇନକମିଂ କଲ୍"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"ଚାଲିଥିବା କଲ୍"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ଏକ ଇନକମିଂ କଲକୁ ସ୍କ୍ରିନ୍ କରୁଛି"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ଚୟନିତ</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ଚୟନିତ</item> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index a717af6ae89b..5c96f88b9bab 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"ਸਿਰਫ਼ ਵਾਈ-ਫਾਈ"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> ਬੈਕਅੱਪ ਕਾਲਿੰਗ"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ਅੱਗੇ ਨਹੀਂ ਭੇਜਿਆ ਗਿਆ"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ਸਕਿੰਟਾਂ ਬਾਅਦ"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨਹੀਂ ਹੈ।"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ਉਂਗਲ <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਤੀਕ"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"ਰੰਗ ਪਲਟਨਾ"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"ਰੰਗ ਸੁਧਾਈ"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ਚਮਕ ਘਟਾਓ"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਕੁੰਜੀਆਂ ਨੂੰ 3 ਸਕਿੰਟਾਂ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"ਵੱਡਾ ਕਰੋ"</string> <string name="close_button_text" msgid="10603510034455258">"ਬੰਦ ਕਰੋ"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"ਜਵਾਬ ਦਿਓ"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"ਅਸਵੀਕਾਰ ਕਰੋ"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"ਸਮਾਪਤ ਕਰੋ"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ਇਨਕਮਿੰਗ ਕਾਲ"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"ਜਾਰੀ ਕਾਲ"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ਇਨਕਮਿੰਗ ਕਾਲ ਦੀ ਸਕ੍ਰੀਨਿੰਗ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index f73b38246e5a..612a0e52957c 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -585,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Czujnik jest tymczasowo wyłączony."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Użyj odcisku palca, by kontynuować"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odcisku palca"</string> @@ -1708,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Użyj skrótu"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Odwrócenie kolorów"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcja kolorów"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zmniejsz jasność"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została włączona."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została wyłączona."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Naciśnij i przytrzymaj oba przyciski głośności przez trzy sekundy, by użyć usługi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1942,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksymalizuj"</string> <string name="close_button_text" msgid="10603510034455258">"Zamknij"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Odbierz"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Odrzuć"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Rozłącz"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Połączenie przychodzące"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Trwa połączenie"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtruję połączenie przychodzące"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="few">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="many">Wybrano <xliff:g id="COUNT_1">%1$d</xliff:g></item> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 693af83522e7..f54635bad3b0 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use sua impressão digital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir brilho"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizar"</string> <string name="close_button_text" msgid="10603510034455258">"Fechar"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Atender"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Recusar"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Desligar"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Chamada recebida"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chamada em andamento"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando uma chamada recebida"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionado</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index e00034acf491..c57e0db40b9d 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporariamente desativado."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Utilize a sua impressão digital para continuar."</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizar atalho"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção da cor"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir o brilho"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas do volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume premidas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Prima sem soltar as teclas de volume durante três segundos para utilizar o serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizar"</string> <string name="close_button_text" msgid="10603510034455258">"Fechar"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Atender"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Recusar"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Desligar"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Chamada recebida"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chamada em curso"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"A filtrar uma chamada recebida…"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 693af83522e7..f54635bad3b0 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Use sua impressão digital para continuar"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Usar atalho"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversão de cores"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Correção de cor"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduzir brilho"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Toque nos dois botões de volume e os mantenha pressionados por três segundo para usar o <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizar"</string> <string name="close_button_text" msgid="10603510034455258">"Fechar"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Atender"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Recusar"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Desligar"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Chamada recebida"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Chamada em andamento"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Filtrando uma chamada recebida"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionado</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 5fd6f1a0634b..9096b8c77493 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -582,6 +582,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzorul este dezactivat temporar."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Folosiți amprenta pentru a continua"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pictograma amprentă"</string> @@ -1686,6 +1687,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utilizați comanda rapidă"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversarea culorilor"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Corecția culorii"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Reduceți luminozitatea"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S-au apăsat lung tastele de volum. S-a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S-au apăsat lung tastele de volum. S-a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Apăsați ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1911,6 +1913,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximizați"</string> <string name="close_button_text" msgid="10603510034455258">"Închideți"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Răspundeți"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Respingeți"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Încheiați"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Apel primit"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Apel în desfășurare"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Se filtrează un apel primit"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> selectate</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selectate</item> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index d1cd374d2bc7..df2906f348b5 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -585,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сканер отпечатков пальцев временно отключен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Отпечаток <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Чтобы продолжить, используйте цифровой отпечаток"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок отпечатка пальца"</string> @@ -1708,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Использовать быстрое включение"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Инверсия цветов"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Коррекция цвета"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Уменьшение яркости"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" включена."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Использован жест с кнопками регулировки громкости. Функция \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\" отключена."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Чтобы использовать сервис \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\", нажмите и удерживайте обе клавиши громкости в течение трех секунд."</string> @@ -1942,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Развернуть"</string> <string name="close_button_text" msgid="10603510034455258">"Закрыть"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Ответить"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Отклонить"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Завершить"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Входящий вызов"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Текущий вызов"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Фильтрация входящего вызова"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="few">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index d102183f25ad..b061248b5bfc 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ඇඟිලි <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ඉදිරියට යාමට ඔබගේ ඇඟිලි සලකුණ භාවිත කරන්න"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ඇඟිලි සලකුණු නිරූපකය"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"කෙටිමඟ භාවිතා කරන්න"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"වර්ණ අපවර්තනය"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"වර්ණ නිවැරදි කිරීම"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"දීප්තිය අඩු කරන්න"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාත්මකයි."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"හඬ පරිමා යතුරු අල්ලා ගන්න <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ක්රියාවිරහිතයි."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> භාවිත කිරීමට හඬ පරිමා යතුරු දෙකම තත්පර තුනකට ඔබාගෙන සිටින්න"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"විහිදන්න"</string> <string name="close_button_text" msgid="10603510034455258">"වසන්න"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"පිළිතුරු දෙ."</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"ප්රතික්ෂේප ක"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"විසන්ධි කරන්න"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"එන ඇමතුම"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"කරගෙන යන ඇමතුම"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"එන ඇමතුමක් පරීක්ෂා කරන්න"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index ffa4b26589d5..dcf19f734514 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -585,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasne vypnutý."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Pokračujte nasnímaním odtlačku prsta"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odtlačku prsta"</string> @@ -1708,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Použiť skratku"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzia farieb"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Úprava farieb"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zníženie jasu"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pridržali ste tlačidlá hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vypnutá."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Ak chcete používať službu <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, pridržte tri sekundy oba klávesy hlasitosti"</string> @@ -1942,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximalizovať"</string> <string name="close_button_text" msgid="10603510034455258">"Zavrieť"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Prijať"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Odmietnuť"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Zložiť"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Prichádzajúci hovor"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Prebiehajúci hovor"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Preveruje sa prichádzajúci hovor"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="few">Vybrané: <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="many">Vybrané: <xliff:g id="COUNT_1">%1$d</xliff:g></item> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index d09ef047c624..88bb116a9c77 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -150,8 +150,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Samo Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"Pomožno klicanje prek operaterja <xliff:g id="SPN">%s</xliff:g>"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ni posredovano"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po toliko sekundah: <xliff:g id="TIME_DELAY">{2}</xliff:g>"</string> @@ -586,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Uporabite prstni odtis, če želite nadaljevati."</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona prstnih odtisov"</string> @@ -1709,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Uporabi bližnjico"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverzija barv"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Popravljanje barv"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Zmanjšanje svetlosti"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je vklopljena."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tipki za glasnost sta pridržani. Storitev <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je izklopljena."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string> @@ -1943,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimiziraj"</string> <string name="close_button_text" msgid="10603510034455258">"Zapri"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Sprejmi"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Zavrni"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Prekini klic"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Dohodni klic"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Aktivni klic"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Preverjanje dohodnega klica"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> izbran</item> <item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> izbrana</item> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 592e54ddceb9..b5eaa7a752fd 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensori është çaktivizuar përkohësisht."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Përdor gjurmën e gishtit për të vazhduar"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona e gjurmës së gishtit"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Përdor shkurtoren"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Kthimi i ngjyrës"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Korrigjimi i ngjyrës"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Redukto ndriçimin"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tastet e volumit të mbajtura shtypur. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> i aktivizuar."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tastet e volumit të mbajtura shtypur. U çaktivizua \"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\"."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Shtyp dhe mbaj shtypur të dy butonat e volumit për tre sekonda për të përdorur <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimizo"</string> <string name="close_button_text" msgid="10603510034455258">"Mbyll"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Përgjigju"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Refuzo"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Mbyll"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Telefonatë hyrëse"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Telefonatë në vazhdim"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Po filtron një telefonatë hyrëse"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> të zgjedhura</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> i zgjedhur</item> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 65037a058067..d50f659bbc31 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -582,6 +582,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензор је привремено онемогућен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Наставите помоћу отиска прста"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона отиска прста"</string> @@ -1686,6 +1687,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Користи пречицу"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Инверзија боја"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Корекција боја"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Смањите осветљеност"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је укључена."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Држали сте тастере за јачину звука. Услуга <xliff:g id="SERVICE_NAME">%1$s</xliff:g> је искључена."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Притисните и задржите оба тастера за јачину звука три секунде да бисте користили <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1911,6 +1913,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Увећај"</string> <string name="close_button_text" msgid="10603510034455258">"Затвори"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Одговори"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Одбиј"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Прекини везу"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Долазни позив"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Позив је у току"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Проверава се долазни позив"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one">Изабрана је <xliff:g id="COUNT_1">%1$d</xliff:g> ставка</item> <item quantity="few">Изабране су <xliff:g id="COUNT_1">%1$d</xliff:g> ставке</item> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index ef7a102fa257..892272ab15a0 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Fortsätt med hjälp av ditt fingeravtryck"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon för fingeravtryck"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Använd kortkommandot"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Inverterade färger"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Färgkorrigering"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Minska ljusstyrkan"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har aktiverats."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volymknapparna har tryckts ned. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> har inaktiverats."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Tryck och håll båda volymknapparna i tre sekunder för att använda <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maximera"</string> <string name="close_button_text" msgid="10603510034455258">"Stäng"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Svara"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Avvisa"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Lägg på"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Inkommande samtal"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Pågående samtal"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Ett inkommande samtal förhandsgranskas"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> har valts</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> har valts</item> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index cc82f4ec8fea..093ebb17b8bd 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Kitambuzi kimezimwa kwa muda."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Kidole cha <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Tumia alama ya kidole chako ili uendelee"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Aikoni ya alama ya kidole"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tumia Njia ya Mkato"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Ugeuzaji rangi"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Usahihishaji wa rangi"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Punguza Ung\'aavu"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Vitufe vya sauti vilivyoshikiliwa. Umewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Vitufe vya sauti vimeshikiliwa. Umezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Panua"</string> <string name="close_button_text" msgid="10603510034455258">"Funga"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Jibu"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Kataa"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Kata simu"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Simu uliyopigiwa"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Simu inayoendelea"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Inachuja simu unayopigiwa"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> vimechaguliwa</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kimechaguliwa</item> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index ca90171d50ce..bc08a58b1906 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"கைரேகை <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"தொடர்வதற்கு கைரேகையைப் பயன்படுத்துங்கள்"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"கைரேகை ஐகான்"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ஷார்ட்கட்டைப் பயன்படுத்து"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"கலர் இன்வெர்ஷன்"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"வண்ணத் திருத்தம்"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ஒளிர்வைக் குறைத்தல்"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"பெரிதாக்கு"</string> <string name="close_button_text" msgid="10603510034455258">"மூடு"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"பதிலளி"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"நிராகரி"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"துண்டி"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"உள்வரும் அழைப்பு"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"செயலில் இருக்கும் அழைப்பு"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"உள்வரும் அழைப்பை மதிப்பாய்வு செய்கிறது"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டன</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> தேர்ந்தெடுக்கப்பட்டது</item> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index b0726e811d47..1f783bef81f7 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Wi-Fi మాత్రమే"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> బ్యాకప్ కాలింగ్"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ఫార్వార్డ్ చేయబడలేదు"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> సెకన్ల తర్వాత <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"వేలు <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"కొనసాగించడానికి మీ వేలిముద్రను ఉపయోగించండి"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"వేలిముద్ర చిహ్నం"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"సత్వరమార్గాన్ని ఉపయోగించు"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"కలర్ మార్పిడి"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"కలర్ సరిచేయడం"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ప్రకాశాన్ని తగ్గించండి"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"వాల్యూమ్ కీలు నొక్కి ఉంచబడ్డాయి. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ని ఉపయోగించడానికి వాల్యూమ్ కీలు రెండింటినీ 3 సెకన్లు నొక్కి ఉంచండి"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"గరిష్టీకరించు"</string> <string name="close_button_text" msgid="10603510034455258">"మూసివేయి"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"సమాధానం ఇవ్వు"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"తిరస్కరించండి"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"కాల్ ముగించు"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"ఇన్కమింగ్ కాల్"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"కాల్ కొనసాగుతోంది"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"ఇన్కమింగ్ కాల్ను స్క్రీన్ చేయండి"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఎంచుకోబడ్డాయి</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 5079f232091b..f5ed8a1bae18 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"ใช้ลายนิ้วมือของคุณเพื่อดำเนินการต่อ"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ไอคอนลายนิ้วมือ"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ใช้ทางลัด"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"การกลับสี"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"การแก้สี"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"ลดความสว่าง"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว เปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว ปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"กดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 3 วินาทีเพื่อใช้ <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"ขยายใหญ่สุด"</string> <string name="close_button_text" msgid="10603510034455258">"ปิด"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"รับสาย"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"ปฏิเสธ"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"วางสาย"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"สายเรียกเข้า"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"สายที่สนทนาอยู่"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"กำลังสกรีนสายเรียกเข้า"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">เลือกไว้ <xliff:g id="COUNT_1">%1$d</xliff:g> รายการ</item> <item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 81bfe5258284..d1b506cbef20 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Pansamantalang na-disable ang sensor."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Gamitin ang iyong fingerprint para magpatuloy"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icon ng fingerprint"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gamitin ang Shortcut"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Pag-invert ng Kulay"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Pagwawasto ng Kulay"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Bawasan ang Liwanag"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Pinindot nang matagal ang volume keys. Na-on ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Pinindot nang matagal ang volume keys. Na-off ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Pindutin nang matagal ang parehong volume key sa loob ng tatlong segundo para magamit ang <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"I-maximize"</string> <string name="close_button_text" msgid="10603510034455258">"Isara"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Sagutin"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Tanggihan"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Ibaba"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Papasok na tawag"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Kasalukuyang tawag"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Nagsi-screen ng papasok na tawag"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 7095bb8c5875..23cf1bd37d04 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensör geçici olarak devre dışı bırakıldı."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Devam etmek için parmak izinizi kullanın"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Parmak izi simgesi"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Kısayolu Kullan"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Rengi Ters Çevirme"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Renk Düzeltme"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Parlaklığı Azaltma"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> açıldı."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ses tuşlarını basılı tuttunuz. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> kapatıldı."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> hizmetini kullanmak için her iki ses tuşunu basılı tutun"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Ekranı Kapla"</string> <string name="close_button_text" msgid="10603510034455258">"Kapat"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Yanıtla"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Reddet"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Kapat"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Gelen çağrı"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Devam eden çağrı"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Gelen arama süzülüyor"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> öğe seçildi</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe seçildi</item> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 9864b4b4e4a4..7f68ddd4a36b 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -585,6 +585,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик тимчасово вимкнено."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Відбиток пальця <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Щоб продовжити, скористайтеся своїм відбитком пальця"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок відбитка пальця"</string> @@ -1708,6 +1709,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Використовувати ярлик"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Інверсія кольорів"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Корекція кольорів"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Зменшення яскравості"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> увімкнено."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Утримано клавіші гучності. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> вимкнено."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string> @@ -1942,6 +1944,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Розгорнути"</string> <string name="close_button_text" msgid="10603510034455258">"Закрити"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Відповісти"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Відхилити"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Завершити"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Вхідний виклик"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Активний виклик"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Фільтрування вхідного виклику"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="few">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 64fb2fc414e2..7935744ce9ff 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -148,8 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"صرف Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <!-- no translation found for crossSimFormat_spn_cross_sim_calling (5620807020002879057) --> - <skip /> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"<xliff:g id="SPN">%s</xliff:g> بیک اپ کالنگ"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : فارورڈ نہیں کی گئی"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> بعد از <xliff:g id="TIME_DELAY">{2}</xliff:g> سیکنڈ"</string> @@ -580,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"سینسر عارضی طور غیر فعال ہے۔"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"جاری رکھنے کیلئے اپنا فنگر پرنٹ استعمال کریں"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"فنگر پرنٹ آئیکن"</string> @@ -1665,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"شارٹ کٹ استعمال کریں"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"رنگوں کی تقلیب"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"رنگ کی تصحیح"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"چمک کم کریں"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آن ہے۔"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"والیوم کی کلیدوں کو دبائے رکھا گیا۔ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> آف ہے۔"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> کا استعمال کرنے کے لیے 3 سیکنڈ تک والیوم کی دونوں کلیدوں کو چھوئیں اور دبائے رکھیں"</string> @@ -1881,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"بڑا کریں"</string> <string name="close_button_text" msgid="10603510034455258">"بند کریں"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"مسترد کریں"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"منقطع کر دیں"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"اِن کمنگ کال"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"جاری کال"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"اِن کمنگ کال کی اسکریننگ"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> منتخب کردہ</item> <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> منتخب کردہ</item> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 6612cc9a875a..bdba644b56d3 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu qurilmada barmoq izi skaneri mavjud emas."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor vaqtincha faol emas."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Barmoq izi <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Davom etish uchun barmoq izingizdan foydalaning"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmoq izi belgisi"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Tezkor ishga tushirishdan foydalanish"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Ranglarni akslantirish"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Rangni tuzatish"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Yorqinlikni pasaytirish"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> yoqildi."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tovush tugmalari bosib turildi. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> faolsizlantirildi."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> xizmatidan foydalanish uchun ikkala ovoz balandligi tugmalarini uzoq bosib turing"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Maksimallashtirish"</string> <string name="close_button_text" msgid="10603510034455258">"Yopish"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Javob berish"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Rad etish"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Tugatish"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Kiruvchi chaqiruv"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Joriy chaqiruv"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Kiruvchi chaqiruvni filtrlash"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">Belgilandi: <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="one">Belgilandi: <xliff:g id="COUNT_0">%1$d</xliff:g></item> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 8f8e0bce3409..745550cc1757 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Đã tạm thời tắt cảm biến."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Sử dụng dấu vân tay của bạn để tiếp tục"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Biểu tượng vân tay"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sử dụng phím tắt"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Đảo màu"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Chỉnh màu"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Giảm độ sáng"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã bật."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bạn đã giữ các phím âm lượng. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> đã tắt."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Nhấn và giữ đồng thời cả hai phím âm lượng trong 3 giây để sử dụng <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Tối đa hóa"</string> <string name="close_button_text" msgid="10603510034455258">"Đóng"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Trả lời"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Từ chối"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Kết thúc"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Cuộc gọi đến"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Cuộc gọi đang thực hiện"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Đang sàng lọc cuộc gọi đến"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">Đã chọn <xliff:g id="COUNT_1">%1$d</xliff:g></item> <item quantity="one">Đã chọn <xliff:g id="COUNT_0">%1$d</xliff:g></item> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index af5f846d368b..56182394a466 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"传感器已暂时停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"使用指纹完成验证才能继续"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指纹图标"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用快捷方式"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"颜色反转"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"调低亮度"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已开启。"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已关闭。"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同时按住两个音量键 3 秒钟即可使用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"最大化"</string> <string name="close_button_text" msgid="10603510034455258">"关闭"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>:<xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"接听"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"拒接"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"挂断"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"来电"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"正在通话"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"正在过滤来电"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">已选择 <xliff:g id="COUNT_1">%1$d</xliff:g> 项</item> <item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 65586f7f1b09..47651c799aa1 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -148,7 +148,7 @@ <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"只限 Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> - <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"「<xliff:g id="SPN">%s</xliff:g>」備用通話網路"</string> + <string name="crossSimFormat_spn_cross_sim_calling" msgid="5620807020002879057">"「<xliff:g id="SPN">%s</xliff:g>」備用通話"</string> <string name="cfTemplateNotForwarded" msgid="862202427794270501">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:尚未轉接"</string> <string name="cfTemplateForwarded" msgid="9132506315842157860">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> 於 <xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後轉接"</string> @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"請使用您的指紋繼續"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用快速鍵"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"色彩反轉"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"調低亮度"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已開啟。"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。<xliff:g id="SERVICE_NAME">%1$s</xliff:g> 已關閉。"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"㩒住兩個音量鍵 3 秒就可以用 <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"最大化"</string> <string name="close_button_text" msgid="10603510034455258">"關閉"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>:<xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"接聽"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"拒接"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"掛斷"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"來電"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"通話中"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"正在過濾來電"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item> <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 6facceb39df7..71292c3d9615 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"使用指紋完成驗證才能繼續操作"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用捷徑"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"色彩反轉"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"調低亮度"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已開啟。"</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已關閉。"</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"同時按住調低及調高音量鍵三秒即可使用「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"最大化"</string> <string name="close_button_text" msgid="10603510034455258">"關閉"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>:<xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"接聽"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"拒接"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"掛斷"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"來電"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"通話中"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"正在過濾來電"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="other">已選取 <xliff:g id="COUNT_1">%1$d</xliff:g> 個項目</item> <item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 3b22e9435462..6202ba84dc3e 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -579,6 +579,7 @@ <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Inzwa ikhutshazwe okwesikhashana."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"Sebenzisa izigxivizo zakho zeminwe ukuze uqhubeke"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Isithonjana sezigxivizo zeminwe"</string> @@ -1664,6 +1665,7 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sebenzisa isinqamuleli"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"Ukuguqulwa kombala"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"Ukulungiswa kombala"</string> + <string name="reduce_bright_colors_feature_name" msgid="6222956501418407642">"Nciphisa ukukhanya"</string> <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivuliwe."</string> <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Ubambe okhiye bevolumu. I-<xliff:g id="SERVICE_NAME">%1$s</xliff:g> ivaliwe."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Cindezela uphinde ubambe bobabili okhiye bevolumu ngamasekhondi amathathu ukuze usebenzise i-<xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string> @@ -1880,6 +1882,12 @@ <string name="maximize_button_text" msgid="4258922519914732645">"Khulisa"</string> <string name="close_button_text" msgid="10603510034455258">"Vala"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"Phendula"</string> + <string name="call_notification_decline_action" msgid="3700345945214000726">"Yenqaba"</string> + <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Vala Ucingo"</string> + <string name="call_notification_incoming_text" msgid="6143109825406638201">"Ikholi engenayo"</string> + <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Ikholi eqhubekayo"</string> + <string name="call_notification_screening_text" msgid="8396931408268940208">"Ukuveza ikholi engenayo"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item> <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index faa2157be302..59285d794045 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3205,6 +3205,10 @@ panning to scaling the magnification viewport. --> <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item> + <!-- Whether to support magnification area. If not enabled, it would hide the entry in + magnification settings and adjust the default magnification capability. --> + <bool name="config_magnification_area">true</bool> + <!-- If true, the display will be shifted around in ambient mode. --> <bool name="config_enableBurnInProtection">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f66d33b02b69..50809140f66a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4174,6 +4174,8 @@ <java-symbol type="string" name="turn_on_magnification_settings_action" /> <java-symbol type="string" name="dismiss_action" /> + <java-symbol type="bool" name="config_magnification_area" /> + <java-symbol type="bool" name="config_trackerAppNeedsPermissions"/> <!-- Package with global data query permissions for AppSearch --> diff --git a/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java deleted file mode 100644 index 7769c28202f2..000000000000 --- a/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.os.Parcel; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test of {@link AngleMeasurement}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class AngleMeasurementTest { - private static final double EPSILON = 0.00000000001; - - @Test - public void testBuilder() { - double radians = 0.1234; - double errorRadians = 0.5678; - double confidence = 0.5; - - AngleMeasurement.Builder builder = new AngleMeasurement.Builder(); - tryBuild(builder, false); - - builder.setRadians(radians); - tryBuild(builder, false); - - builder.setErrorRadians(errorRadians); - tryBuild(builder, false); - - builder.setConfidenceLevel(confidence); - AngleMeasurement measurement = tryBuild(builder, true); - - assertEquals(measurement.getRadians(), radians, 0); - assertEquals(measurement.getErrorRadians(), errorRadians, 0); - assertEquals(measurement.getConfidenceLevel(), confidence, 0); - } - - private AngleMeasurement tryBuild(AngleMeasurement.Builder builder, boolean expectSuccess) { - AngleMeasurement measurement = null; - try { - measurement = builder.build(); - if (!expectSuccess) { - fail("Expected AngleMeasurement.Builder.build() to fail, but it succeeded"); - } - } catch (IllegalStateException e) { - if (expectSuccess) { - fail("Expected AngleMeasurement.Builder.build() to succeed, but it failed"); - } - } - return measurement; - } - - @Test - public void testParcel() { - Parcel parcel = Parcel.obtain(); - AngleMeasurement measurement = UwbTestUtils.getAngleMeasurement(); - measurement.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AngleMeasurement fromParcel = AngleMeasurement.CREATOR.createFromParcel(parcel); - assertEquals(measurement, fromParcel); - } -} diff --git a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java deleted file mode 100644 index 9394dec7f46f..000000000000 --- a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.os.Parcel; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test of {@link AngleOfArrivalMeasurement}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class AngleOfArrivalMeasurementTest { - - @Test - public void testBuilder() { - AngleMeasurement azimuth = UwbTestUtils.getAngleMeasurement(); - AngleMeasurement altitude = UwbTestUtils.getAngleMeasurement(); - - AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder(); - tryBuild(builder, false); - - builder.setAltitude(altitude); - tryBuild(builder, false); - - builder.setAzimuth(azimuth); - AngleOfArrivalMeasurement measurement = tryBuild(builder, true); - - assertEquals(azimuth, measurement.getAzimuth()); - assertEquals(altitude, measurement.getAltitude()); - } - - private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) { - return new AngleMeasurement.Builder() - .setRadians(radian) - .setErrorRadians(error) - .setConfidenceLevel(confidence) - .build(); - } - - private AngleOfArrivalMeasurement tryBuild(AngleOfArrivalMeasurement.Builder builder, - boolean expectSuccess) { - AngleOfArrivalMeasurement measurement = null; - try { - measurement = builder.build(); - if (!expectSuccess) { - fail("Expected AngleOfArrivalMeasurement.Builder.build() to fail"); - } - } catch (IllegalStateException e) { - if (expectSuccess) { - fail("Expected AngleOfArrivalMeasurement.Builder.build() to succeed"); - } - } - return measurement; - } - - @Test - public void testParcel() { - Parcel parcel = Parcel.obtain(); - AngleOfArrivalMeasurement measurement = UwbTestUtils.getAngleOfArrivalMeasurement(); - measurement.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - AngleOfArrivalMeasurement fromParcel = - AngleOfArrivalMeasurement.CREATOR.createFromParcel(parcel); - assertEquals(measurement, fromParcel); - } -} diff --git a/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java deleted file mode 100644 index 439c884723be..000000000000 --- a/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.os.Parcel; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test of {@link DistanceMeasurement}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class DistanceMeasurementTest { - private static final double EPSILON = 0.00000000001; - - @Test - public void testBuilder() { - double meters = 0.12; - double error = 0.54; - double confidence = 0.99; - - DistanceMeasurement.Builder builder = new DistanceMeasurement.Builder(); - tryBuild(builder, false); - - builder.setMeters(meters); - tryBuild(builder, false); - - builder.setErrorMeters(error); - tryBuild(builder, false); - - builder.setConfidenceLevel(confidence); - DistanceMeasurement measurement = tryBuild(builder, true); - - assertEquals(meters, measurement.getMeters(), 0); - assertEquals(error, measurement.getErrorMeters(), 0); - assertEquals(confidence, measurement.getConfidenceLevel(), 0); - } - - private DistanceMeasurement tryBuild(DistanceMeasurement.Builder builder, - boolean expectSuccess) { - DistanceMeasurement measurement = null; - try { - measurement = builder.build(); - if (!expectSuccess) { - fail("Expected DistanceMeasurement.Builder.build() to fail"); - } - } catch (IllegalStateException e) { - if (expectSuccess) { - fail("Expected DistanceMeasurement.Builder.build() to succeed"); - } - } - return measurement; - } - - @Test - public void testParcel() { - Parcel parcel = Parcel.obtain(); - DistanceMeasurement measurement = UwbTestUtils.getDistanceMeasurement(); - measurement.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - DistanceMeasurement fromParcel = - DistanceMeasurement.CREATOR.createFromParcel(parcel); - assertEquals(measurement, fromParcel); - } -} diff --git a/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java deleted file mode 100644 index edd4d08992ba..000000000000 --- a/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.os.Parcel; -import android.os.SystemClock; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test of {@link RangingMeasurement}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class RangingMeasurementTest { - - @Test - public void testBuilder() { - int status = RangingMeasurement.RANGING_STATUS_SUCCESS; - UwbAddress address = UwbTestUtils.getUwbAddress(false); - long time = SystemClock.elapsedRealtimeNanos(); - AngleOfArrivalMeasurement angleMeasurement = UwbTestUtils.getAngleOfArrivalMeasurement(); - DistanceMeasurement distanceMeasurement = UwbTestUtils.getDistanceMeasurement(); - - RangingMeasurement.Builder builder = new RangingMeasurement.Builder(); - - builder.setStatus(status); - tryBuild(builder, false); - - builder.setElapsedRealtimeNanos(time); - tryBuild(builder, false); - - builder.setAngleOfArrivalMeasurement(angleMeasurement); - tryBuild(builder, false); - - builder.setDistanceMeasurement(distanceMeasurement); - tryBuild(builder, false); - - builder.setRemoteDeviceAddress(address); - RangingMeasurement measurement = tryBuild(builder, true); - - assertEquals(status, measurement.getStatus()); - assertEquals(address, measurement.getRemoteDeviceAddress()); - assertEquals(time, measurement.getElapsedRealtimeNanos()); - assertEquals(angleMeasurement, measurement.getAngleOfArrivalMeasurement()); - assertEquals(distanceMeasurement, measurement.getDistanceMeasurement()); - } - - private RangingMeasurement tryBuild(RangingMeasurement.Builder builder, - boolean expectSuccess) { - RangingMeasurement measurement = null; - try { - measurement = builder.build(); - if (!expectSuccess) { - fail("Expected RangingMeasurement.Builder.build() to fail"); - } - } catch (IllegalStateException e) { - if (expectSuccess) { - fail("Expected DistanceMeasurement.Builder.build() to succeed"); - } - } - return measurement; - } - - @Test - public void testParcel() { - Parcel parcel = Parcel.obtain(); - RangingMeasurement measurement = UwbTestUtils.getRangingMeasurement(); - measurement.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - RangingMeasurement fromParcel = RangingMeasurement.CREATOR.createFromParcel(parcel); - assertEquals(measurement, fromParcel); - } -} diff --git a/core/tests/uwbtests/src/android/uwb/RangingReportTest.java b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java deleted file mode 100644 index 64c48ba4b6f4..000000000000 --- a/core/tests/uwbtests/src/android/uwb/RangingReportTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import android.os.Parcel; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.List; - -/** - * Test of {@link RangingReport}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class RangingReportTest { - - @Test - public void testBuilder() { - List<RangingMeasurement> measurements = UwbTestUtils.getRangingMeasurements(5); - - RangingReport.Builder builder = new RangingReport.Builder(); - builder.addMeasurements(measurements); - RangingReport report = tryBuild(builder, true); - verifyMeasurementsEqual(measurements, report.getMeasurements()); - - - builder = new RangingReport.Builder(); - for (RangingMeasurement measurement : measurements) { - builder.addMeasurement(measurement); - } - report = tryBuild(builder, true); - verifyMeasurementsEqual(measurements, report.getMeasurements()); - } - - private void verifyMeasurementsEqual(List<RangingMeasurement> expected, - List<RangingMeasurement> actual) { - assertEquals(expected.size(), actual.size()); - for (int i = 0; i < expected.size(); i++) { - assertEquals(expected.get(i), actual.get(i)); - } - } - - private RangingReport tryBuild(RangingReport.Builder builder, - boolean expectSuccess) { - RangingReport report = null; - try { - report = builder.build(); - if (!expectSuccess) { - fail("Expected RangingReport.Builder.build() to fail"); - } - } catch (IllegalStateException e) { - if (expectSuccess) { - fail("Expected RangingReport.Builder.build() to succeed"); - } - } - return report; - } - - @Test - public void testParcel() { - Parcel parcel = Parcel.obtain(); - RangingReport report = UwbTestUtils.getRangingReports(5); - report.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - RangingReport fromParcel = RangingReport.CREATOR.createFromParcel(parcel); - assertEquals(report, fromParcel); - } -} diff --git a/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java b/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java deleted file mode 100644 index e5eea26f5d11..000000000000 --- a/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.os.PersistableBundle; -import android.os.RemoteException; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.util.concurrent.Executor; - -/** - * Test of {@link RangingSession}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class RangingSessionTest { - private static final Executor EXECUTOR = UwbTestUtils.getExecutor(); - private static final PersistableBundle PARAMS = new PersistableBundle(); - private static final @RangingSession.Callback.Reason int REASON = - RangingSession.Callback.REASON_GENERIC_ERROR; - - @Test - public void testOnRangingOpened_OnOpenSuccessCalled() { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - verifyOpenState(session, false); - - session.onRangingOpened(); - verifyOpenState(session, true); - - // Verify that the onOpenSuccess callback was invoked - verify(callback, times(1)).onOpened(eq(session)); - verify(callback, times(0)).onClosed(anyInt(), any()); - } - - @Test - public void testOnRangingOpened_CannotOpenClosedSession() { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - - session.onRangingOpened(); - verifyOpenState(session, true); - verify(callback, times(1)).onOpened(eq(session)); - verify(callback, times(0)).onClosed(anyInt(), any()); - - session.onRangingClosed(REASON, PARAMS); - verifyOpenState(session, false); - verify(callback, times(1)).onOpened(eq(session)); - verify(callback, times(1)).onClosed(anyInt(), any()); - - // Now invoke the ranging started callback and ensure the session remains closed - session.onRangingOpened(); - verifyOpenState(session, false); - verify(callback, times(1)).onOpened(eq(session)); - verify(callback, times(1)).onClosed(anyInt(), any()); - } - - @Test - public void testOnRangingClosed_OnClosedCalledWhenSessionNotOpen() { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - verifyOpenState(session, false); - - session.onRangingClosed(REASON, PARAMS); - verifyOpenState(session, false); - - // Verify that the onOpenSuccess callback was invoked - verify(callback, times(0)).onOpened(eq(session)); - verify(callback, times(1)).onClosed(anyInt(), any()); - } - - @Test - public void testOnRangingClosed_OnClosedCalled() { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - session.onRangingStarted(PARAMS); - session.onRangingClosed(REASON, PARAMS); - verify(callback, times(1)).onClosed(anyInt(), any()); - - verifyOpenState(session, false); - session.onRangingClosed(REASON, PARAMS); - verify(callback, times(2)).onClosed(anyInt(), any()); - } - - @Test - public void testOnRangingResult_OnReportReceivedCalled() { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - verifyOpenState(session, false); - - session.onRangingStarted(PARAMS); - verifyOpenState(session, true); - - RangingReport report = UwbTestUtils.getRangingReports(1); - session.onRangingResult(report); - verify(callback, times(1)).onReportReceived(eq(report)); - } - - @Test - public void testStart_CannotStartIfAlreadyStarted() throws RemoteException { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any()); - session.onRangingOpened(); - - session.start(PARAMS); - verify(callback, times(1)).onStarted(any()); - - // Calling start again should throw an illegal state - verifyThrowIllegalState(() -> session.start(PARAMS)); - verify(callback, times(1)).onStarted(any()); - } - - @Test - public void testStop_CannotStopIfAlreadyStopped() throws RemoteException { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any()); - doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any()); - session.onRangingOpened(); - session.start(PARAMS); - - verifyNoThrowIllegalState(session::stop); - verify(callback, times(1)).onStopped(); - - // Calling stop again should throw an illegal state - verifyThrowIllegalState(session::stop); - verify(callback, times(1)).onStopped(); - } - - @Test - public void testReconfigure_OnlyWhenOpened() throws RemoteException { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any()); - doAnswer(new ReconfigureAnswer(session)).when(adapter).reconfigureRanging(any(), any()); - - verifyThrowIllegalState(() -> session.reconfigure(PARAMS)); - verify(callback, times(0)).onReconfigured(any()); - verifyOpenState(session, false); - - session.onRangingOpened(); - verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS)); - verify(callback, times(1)).onReconfigured(any()); - verifyOpenState(session, true); - - session.onRangingStarted(PARAMS); - verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS)); - verify(callback, times(2)).onReconfigured(any()); - verifyOpenState(session, true); - - session.onRangingStopped(); - verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS)); - verify(callback, times(3)).onReconfigured(any()); - verifyOpenState(session, true); - - - session.onRangingClosed(REASON, PARAMS); - verifyThrowIllegalState(() -> session.reconfigure(PARAMS)); - verify(callback, times(3)).onReconfigured(any()); - verifyOpenState(session, false); - } - - @Test - public void testClose_NoCallbackUntilInvoked() throws RemoteException { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - session.onRangingOpened(); - - // Calling close multiple times should invoke closeRanging until the session receives - // the onClosed callback. - int totalCallsBeforeOnRangingClosed = 3; - for (int i = 1; i <= totalCallsBeforeOnRangingClosed; i++) { - session.close(); - verifyOpenState(session, true); - verify(adapter, times(i)).closeRanging(handle); - verify(callback, times(0)).onClosed(anyInt(), any()); - } - - // After onClosed is invoked, then the adapter should no longer be called for each call to - // the session's close. - final int totalCallsAfterOnRangingClosed = 2; - for (int i = 1; i <= totalCallsAfterOnRangingClosed; i++) { - session.onRangingClosed(REASON, PARAMS); - verifyOpenState(session, false); - verify(adapter, times(totalCallsBeforeOnRangingClosed)).closeRanging(handle); - verify(callback, times(i)).onClosed(anyInt(), any()); - } - } - - @Test - public void testClose_OnClosedCalled() throws RemoteException { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any()); - session.onRangingOpened(); - - session.close(); - verify(callback, times(1)).onClosed(anyInt(), any()); - } - - @Test - public void testClose_CannotInteractFurther() throws RemoteException { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any()); - session.close(); - - verifyThrowIllegalState(() -> session.start(PARAMS)); - verifyThrowIllegalState(() -> session.reconfigure(PARAMS)); - verifyThrowIllegalState(() -> session.stop()); - verifyNoThrowIllegalState(() -> session.close()); - } - - @Test - public void testOnRangingResult_OnReportReceivedCalledWhenOpen() { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - - assertFalse(session.isOpen()); - session.onRangingStarted(PARAMS); - assertTrue(session.isOpen()); - - // Verify that the onReportReceived callback was invoked - RangingReport report = UwbTestUtils.getRangingReports(1); - session.onRangingResult(report); - verify(callback, times(1)).onReportReceived(report); - } - - @Test - public void testOnRangingResult_OnReportReceivedNotCalledWhenNotOpen() { - SessionHandle handle = new SessionHandle(123); - RangingSession.Callback callback = mock(RangingSession.Callback.class); - IUwbAdapter adapter = mock(IUwbAdapter.class); - RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle); - - assertFalse(session.isOpen()); - - // Verify that the onReportReceived callback was invoked - RangingReport report = UwbTestUtils.getRangingReports(1); - session.onRangingResult(report); - verify(callback, times(0)).onReportReceived(report); - } - - private void verifyOpenState(RangingSession session, boolean expected) { - assertEquals(expected, session.isOpen()); - } - - private void verifyThrowIllegalState(Runnable runnable) { - try { - runnable.run(); - fail(); - } catch (IllegalStateException e) { - // Pass - } - } - - private void verifyNoThrowIllegalState(Runnable runnable) { - try { - runnable.run(); - } catch (IllegalStateException e) { - fail(); - } - } - - abstract class AdapterAnswer implements Answer { - protected RangingSession mSession; - - protected AdapterAnswer(RangingSession session) { - mSession = session; - } - } - - class StartAnswer extends AdapterAnswer { - StartAnswer(RangingSession session) { - super(session); - } - - @Override - public Object answer(InvocationOnMock invocation) { - mSession.onRangingStarted(PARAMS); - return null; - } - } - - class ReconfigureAnswer extends AdapterAnswer { - ReconfigureAnswer(RangingSession session) { - super(session); - } - - @Override - public Object answer(InvocationOnMock invocation) { - mSession.onRangingReconfigured(PARAMS); - return null; - } - } - - class StopAnswer extends AdapterAnswer { - StopAnswer(RangingSession session) { - super(session); - } - - @Override - public Object answer(InvocationOnMock invocation) { - mSession.onRangingStopped(); - return null; - } - } - - class CloseAnswer extends AdapterAnswer { - CloseAnswer(RangingSession session) { - super(session); - } - - @Override - public Object answer(InvocationOnMock invocation) { - mSession.onRangingClosed(REASON, PARAMS); - return null; - } - } -} diff --git a/core/tests/uwbtests/src/android/uwb/SessionHandleTest.java b/core/tests/uwbtests/src/android/uwb/SessionHandleTest.java deleted file mode 100644 index 8b42ff7f62a7..000000000000 --- a/core/tests/uwbtests/src/android/uwb/SessionHandleTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; - -import android.os.Parcel; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test of {@link SessionHandle}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class SessionHandleTest { - - @Test - public void testBasic() { - int handleId = 12; - SessionHandle handle = new SessionHandle(handleId); - assertEquals(handle.getId(), handleId); - } - - @Test - public void testParcel() { - Parcel parcel = Parcel.obtain(); - SessionHandle handle = new SessionHandle(10); - handle.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - SessionHandle fromParcel = SessionHandle.CREATOR.createFromParcel(parcel); - assertEquals(handle, fromParcel); - } -} diff --git a/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java deleted file mode 100644 index ccc88a9a5399..000000000000 --- a/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertEquals; - -import android.os.Parcel; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test of {@link UwbAddress}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class UwbAddressTest { - - @Test - public void testFromBytes_Short() { - runFromBytes(UwbAddress.SHORT_ADDRESS_BYTE_LENGTH); - } - - @Test - public void testFromBytes_Extended() { - runFromBytes(UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH); - } - - private void runFromBytes(int len) { - byte[] addressBytes = getByteArray(len); - UwbAddress address = UwbAddress.fromBytes(addressBytes); - assertEquals(address.size(), len); - assertEquals(addressBytes, address.toBytes()); - } - - private byte[] getByteArray(int len) { - byte[] res = new byte[len]; - for (int i = 0; i < len; i++) { - res[i] = (byte) i; - } - return res; - } - - @Test - public void testParcel_Short() { - runParcel(true); - } - - @Test - public void testParcel_Extended() { - runParcel(false); - } - - private void runParcel(boolean useShortAddress) { - Parcel parcel = Parcel.obtain(); - UwbAddress address = UwbTestUtils.getUwbAddress(useShortAddress); - address.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - UwbAddress fromParcel = UwbAddress.CREATOR.createFromParcel(parcel); - assertEquals(address, fromParcel); - } -} diff --git a/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java b/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java deleted file mode 100644 index 4983bed742fd..000000000000 --- a/core/tests/uwbtests/src/android/uwb/UwbManagerTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import android.content.Context; - -import androidx.test.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test of {@link UwbManager}. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class UwbManagerTest { - - public final Context mContext = InstrumentationRegistry.getContext(); - - @Test - public void testServiceAvailable() { - UwbManager manager = mContext.getSystemService(UwbManager.class); - if (UwbTestUtils.isUwbSupported(mContext)) { - assertNotNull(manager); - } else { - assertNull(manager); - } - } -} diff --git a/libs/WindowManager/Shell/res/drawable/pip_expand.xml b/libs/WindowManager/Shell/res/drawable/pip_expand.xml index c99d81934aab..d36c4f72ecd0 100644 --- a/libs/WindowManager/Shell/res/drawable/pip_expand.xml +++ b/libs/WindowManager/Shell/res/drawable/pip_expand.xml @@ -14,8 +14,8 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="36dp" - android:height="36dp" + android:width="@dimen/pip_expand_action_inner_size" + android:height="@dimen/pip_expand_action_inner_size" android:viewportWidth="36" android:viewportHeight="36"> @@ -25,4 +25,4 @@ android:fillColor="#FFFFFF" android:pathData="M10 21H7v8h8v-3h-5v-5zm-3-6h3v-5h5V7H7v8zm19 11h-5v3h8v-8h-3v5zM21 7v3h5v5h3V7h-8z" /> -</vector>
\ No newline at end of file +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml index bcc850a854de..60456267afef 100644 --- a/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml @@ -15,8 +15,8 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24.0dp" - android:height="24.0dp" + android:width="@dimen/pip_action_inner_size" + android:height="@dimen/pip_action_inner_size" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml index ef9b2d9c1c63..0c469f7abb78 100644 --- a/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml @@ -15,8 +15,8 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" + android:width="@dimen/pip_action_inner_size" + android:height="@dimen/pip_action_inner_size" android:viewportWidth="24" android:viewportHeight="24"> diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml index f12d2cbebc87..8567afa3232c 100644 --- a/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml @@ -15,8 +15,8 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" + android:width="@dimen/pip_action_inner_size" + android:height="@dimen/pip_action_inner_size" android:viewportWidth="24" android:viewportHeight="24"> diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml index b61e98ce2f9f..73ec167f1f6f 100644 --- a/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml @@ -15,8 +15,8 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" + android:width="@dimen/pip_action_inner_size" + android:height="@dimen/pip_action_inner_size" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_skip_next_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_skip_next_white.xml index 040c7e642241..6c5542131ab8 100644 --- a/libs/WindowManager/Shell/res/drawable/pip_ic_skip_next_white.xml +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_skip_next_white.xml @@ -15,8 +15,8 @@ Copyright (C) 2017 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" + android:width="@dimen/pip_action_inner_size" + android:height="@dimen/pip_action_inner_size" android:viewportWidth="24" android:viewportHeight="24"> @@ -25,4 +25,4 @@ Copyright (C) 2017 The Android Open Source Project android:pathData="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z" /> <path android:pathData="M0 0h24v24H0z" /> -</vector>
\ No newline at end of file +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_skip_previous_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_skip_previous_white.xml index b9b94b73a00f..6b5382b662b1 100644 --- a/libs/WindowManager/Shell/res/drawable/pip_ic_skip_previous_white.xml +++ b/libs/WindowManager/Shell/res/drawable/pip_ic_skip_previous_white.xml @@ -15,8 +15,8 @@ Copyright (C) 2017 The Android Open Source Project limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" + android:width="@dimen/pip_action_inner_size" + android:height="@dimen/pip_action_inner_size" android:viewportWidth="24" android:viewportHeight="24"> @@ -25,4 +25,4 @@ Copyright (C) 2017 The Android Open Source Project android:pathData="M6 6h2v12H6zm3.5 6l8.5 6V6z" /> <path android:pathData="M0 0h24v24H0z" /> -</vector>
\ No newline at end of file +</vector> diff --git a/libs/WindowManager/Shell/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml index b581f555c234..9fe024748610 100644 --- a/libs/WindowManager/Shell/res/layout/pip_menu.xml +++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml @@ -40,7 +40,7 @@ android:layout_height="@dimen/pip_expand_action_size" android:layout_gravity="center" android:contentDescription="@string/pip_phone_expand" - android:padding="10dp" + android:gravity="center" android:src="@drawable/pip_expand" android:background="?android:selectableItemBackgroundBorderless" /> </FrameLayout> @@ -72,8 +72,8 @@ android:id="@+id/settings" android:layout_width="@dimen/pip_action_size" android:layout_height="@dimen/pip_action_size" - android:padding="@dimen/pip_action_padding" android:contentDescription="@string/pip_phone_settings" + android:gravity="center" android:src="@drawable/pip_ic_settings" android:background="?android:selectableItemBackgroundBorderless" /> @@ -81,8 +81,8 @@ android:id="@+id/dismiss" android:layout_width="@dimen/pip_action_size" android:layout_height="@dimen/pip_action_size" - android:padding="@dimen/pip_action_padding" android:contentDescription="@string/pip_phone_close" + android:gravity="center" android:src="@drawable/pip_ic_close_white" android:background="?android:selectableItemBackgroundBorderless" /> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/layout/pip_menu_action.xml b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml index 7a026ca63f50..a733b31d9fb0 100644 --- a/libs/WindowManager/Shell/res/layout/pip_menu_action.xml +++ b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml @@ -14,10 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. --> -<ImageButton +<com.android.wm.shell.pip.phone.PipMenuActionView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/pip_action_size" android:layout_height="@dimen/pip_action_size" - android:padding="@dimen/pip_action_padding" android:background="?android:selectableItemBackgroundBorderless" - android:forceHasOverlappingRendering="false" /> + android:forceHasOverlappingRendering="false"> + + <ImageView + android:id="@+id/image" + android:layout_width="@dimen/pip_action_inner_size" + android:layout_height="@dimen/pip_action_inner_size" + android:layout_gravity="center" + android:scaleType="fitXY"/> + +</com.android.wm.shell.pip.phone.PipMenuActionView> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 583964b2f4a4..75bed3777a9d 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -21,14 +21,20 @@ <dimen name="floating_dismiss_gradient_height">250dp</dimen> <!-- The padding around a PiP actions. --> - <dimen name="pip_action_padding">12dp</dimen> + <dimen name="pip_action_padding">16dp</dimen> <!-- The height of the PiP actions container in which the actions are vertically centered. --> <dimen name="pip_action_size">48dp</dimen> - <!-- The width and height of the PiP expand action. --> + <!-- The width and height of the PiP action asset drawn within the container. --> + <dimen name="pip_action_inner_size">20dp</dimen> + + <!-- The width and height of the PiP expand action container. --> <dimen name="pip_expand_action_size">60dp</dimen> + <!-- The width and height of the PiP expand action asset drawn within the container. --> + <dimen name="pip_expand_action_inner_size">28dp</dimen> + <!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect the configuration of the device, so we can't use -land resources. --> <dimen name="pip_between_action_padding_land">8dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActionView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActionView.java new file mode 100644 index 000000000000..f11ae422e837 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActionView.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip.phone; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.wm.shell.R; + +/** + * Container layout wraps single action image view drawn in PiP menu and can restrict the size of + * action image view (see pip_menu_action.xml). + */ +public class PipMenuActionView extends FrameLayout { + private ImageView mImageView; + + public PipMenuActionView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mImageView = findViewById(R.id.image); + } + + /** pass through to internal {@link #mImageView} */ + public void setImageDrawable(Drawable drawable) { + mImageView.setImageDrawable(drawable); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index 1cf3a48e9575..0d64407f649f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -59,7 +59,6 @@ import android.view.ViewRootImpl; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; -import android.widget.ImageButton; import android.widget.LinearLayout; import com.android.wm.shell.R; @@ -407,7 +406,7 @@ public class PipMenuView extends FrameLayout { // Ensure we have as many buttons as actions final LayoutInflater inflater = LayoutInflater.from(mContext); while (mActionsGroup.getChildCount() < mActions.size()) { - final ImageButton actionView = (ImageButton) inflater.inflate( + final PipMenuActionView actionView = (PipMenuActionView) inflater.inflate( R.layout.pip_menu_action, mActionsGroup, false); mActionsGroup.addView(actionView); } @@ -424,7 +423,8 @@ public class PipMenuView extends FrameLayout { && (stackBounds.width() > stackBounds.height()); for (int i = 0; i < mActions.size(); i++) { final RemoteAction action = mActions.get(i); - final ImageButton actionView = (ImageButton) mActionsGroup.getChildAt(i); + final PipMenuActionView actionView = + (PipMenuActionView) mActionsGroup.getChildAt(i); // TODO: Check if the action drawable has changed before we reload it action.getIcon().loadDrawableAsync(mContext, d -> { diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 607c8f11e01a..cf31e4141a6d 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -2414,37 +2414,44 @@ final public class MediaCodec implements PlaybackComponent { * This indicates that the requested key was not found when trying to * perform a decrypt operation. The operation can be retried after adding * the correct decryption key. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_NO_KEY}. */ - public static final int ERROR_NO_KEY = 1; + public static final int ERROR_NO_KEY = MediaDrm.ErrorCodes.ERROR_NO_KEY; /** * This indicates that the key used for decryption is no longer * valid due to license term expiration. The operation can be retried * after updating the expired keys. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_KEY_EXPIRED}. */ - public static final int ERROR_KEY_EXPIRED = 2; + public static final int ERROR_KEY_EXPIRED = MediaDrm.ErrorCodes.ERROR_KEY_EXPIRED; /** * This indicates that a required crypto resource was not able to be * allocated while attempting the requested operation. The operation * can be retried if the app is able to release resources. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_RESOURCE_BUSY} */ - public static final int ERROR_RESOURCE_BUSY = 3; + public static final int ERROR_RESOURCE_BUSY = MediaDrm.ErrorCodes.ERROR_RESOURCE_BUSY; /** * This indicates that the output protection levels supported by the * device are not sufficient to meet the requirements set by the * content owner in the license policy. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_INSUFFICIENT_OUTPUT_PROTECTION} */ - public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; + public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION; /** * This indicates that decryption was attempted on a session that is * not opened, which could be due to a failure to open the session, * closing the session prematurely, or the session being reclaimed * by the resource manager. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_SESSION_NOT_OPENED} */ - public static final int ERROR_SESSION_NOT_OPENED = 5; + public static final int ERROR_SESSION_NOT_OPENED = + MediaDrm.ErrorCodes.ERROR_SESSION_NOT_OPENED; /** * This indicates that an operation was attempted that could not be @@ -2453,23 +2460,28 @@ final public class MediaCodec implements PlaybackComponent { * device security features that aren't supported by the device, * or due to an internal error in the crypto system that prevents * the specified security policy from being met. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_UNSUPPORTED_OPERATION} */ - public static final int ERROR_UNSUPPORTED_OPERATION = 6; + public static final int ERROR_UNSUPPORTED_OPERATION = + MediaDrm.ErrorCodes.ERROR_UNSUPPORTED_OPERATION; /** * This indicates that the security level of the device is not * sufficient to meet the requirements set by the content owner * in the license policy. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_INSUFFICIENT_SECURITY} */ - public static final int ERROR_INSUFFICIENT_SECURITY = 7; + public static final int ERROR_INSUFFICIENT_SECURITY = + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_SECURITY; /** * This indicates that the video frame being decrypted exceeds * the size of the device's protected output buffers. When * encountering this error the app should try playing content * of a lower resolution. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_FRAME_TOO_LARGE} */ - public static final int ERROR_FRAME_TOO_LARGE = 8; + public static final int ERROR_FRAME_TOO_LARGE = MediaDrm.ErrorCodes.ERROR_FRAME_TOO_LARGE; /** * This error indicates that session state has been @@ -2477,26 +2489,37 @@ final public class MediaCodec implements PlaybackComponent { * of retaining crypto session state across device * suspend/resume. The session must be closed and a new * session opened to resume operation. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_LOST_STATE} */ - public static final int ERROR_LOST_STATE = 9; + public static final int ERROR_LOST_STATE = MediaDrm.ErrorCodes.ERROR_LOST_STATE; /** @hide */ @IntDef({ - ERROR_NO_KEY, - ERROR_KEY_EXPIRED, - ERROR_RESOURCE_BUSY, - ERROR_INSUFFICIENT_OUTPUT_PROTECTION, - ERROR_SESSION_NOT_OPENED, - ERROR_UNSUPPORTED_OPERATION, - ERROR_INSUFFICIENT_SECURITY, - ERROR_FRAME_TOO_LARGE, - ERROR_LOST_STATE + MediaDrm.ErrorCodes.ERROR_NO_KEY, + MediaDrm.ErrorCodes.ERROR_KEY_EXPIRED, + MediaDrm.ErrorCodes.ERROR_RESOURCE_BUSY, + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION, + MediaDrm.ErrorCodes.ERROR_SESSION_NOT_OPENED, + MediaDrm.ErrorCodes.ERROR_UNSUPPORTED_OPERATION, + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_SECURITY, + MediaDrm.ErrorCodes.ERROR_FRAME_TOO_LARGE, + MediaDrm.ErrorCodes.ERROR_LOST_STATE, + MediaDrm.ErrorCodes.ERROR_GENERIC_OEM, + MediaDrm.ErrorCodes.ERROR_GENERIC_PLUGIN, + MediaDrm.ErrorCodes.ERROR_LICENSE_PARSE, + MediaDrm.ErrorCodes.ERROR_MEDIA_FRAMEWORK, + MediaDrm.ErrorCodes.ERROR_ZERO_SUBSAMPLES }) @Retention(RetentionPolicy.SOURCE) public @interface CryptoErrorCode {} /** - * Retrieve the error code associated with a CryptoException + * Returns error code associated with this {@link CryptoException}. + * <p> + * Please refer to {@link MediaDrm.ErrorCodes} for the general error + * handling strategy and details about each possible return value. + * + * @return an error code defined in {@link MediaDrm.ErrorCodes}. */ @CryptoErrorCode public int getErrorCode() { diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index adb8a54c0167..f7467a636024 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -23,7 +23,11 @@ import android.annotation.Nullable; import android.annotation.StringDef; import android.annotation.TestApi; import android.app.ActivityThread; +import android.app.Application; import android.compat.annotation.UnsupportedAppUsage; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; import android.media.metrics.PlaybackComponent; import android.os.Handler; import android.os.HandlerExecutor; @@ -39,7 +43,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.time.Instant; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -144,6 +151,7 @@ public final class MediaDrm implements AutoCloseable { private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; private long mNativeContext; + private final String mAppPackageName; /** * Specify no certificate type @@ -281,16 +289,371 @@ public final class MediaDrm implements AutoCloseable { /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ + mAppPackageName = ActivityThread.currentOpPackageName(); native_setup(new WeakReference<MediaDrm>(this), - getByteArrayFromUUID(uuid), ActivityThread.currentOpPackageName()); + getByteArrayFromUUID(uuid), mAppPackageName); mCloseGuard.open("release"); } /** - * Thrown when an unrecoverable failure occurs during a MediaDrm operation. - * Extends java.lang.IllegalStateException with the addition of an error + * Error codes that may be returned from {@link + * MediaDrmStateException#getErrorCode()} and {@link + * MediaCodec.CryptoException#getErrorCode()} + * <p> + * The description of each error code includes steps that may be taken to + * resolve the error condition. For some errors however, a recovery action + * cannot be predetermined. The description of those codes refers to a + * general strategy for handling the error condition programmatically, which + * is to try the following in listed order until successful: + * <ol> + * <li> retry the operation </li> + * <li> if the operation is related to a session, {@link + * #closeSession(byte[]) close} the session, {@link #openSession() open} a + * new session, and retry the operation </li> + * <li> {@link #close() close} the {@link MediaDrm} instance and any other + * related components such as the {@link MediaCodec codec} and retry + * playback, or </li> + * <li> try using a different configuration of the {@link MediaDrm} plugin, + * such as a different {@link #openSession(int) security level}. </li> + * </ol> + * <p> + * If the problem still persists after all the aforementioned steps, please + * report the failure to the {@link MediaDrm} plugin vendor along with the + * {@link LogMessage log messages} returned by {@link + * MediaDrm#getLogMessages()}, and a bugreport if possible. + */ + public final static class ErrorCodes { + private ErrorCodes() {} + + /** + * ERROR_UNKNOWN is used where no other defined error code is applicable + * to the current failure. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_UNKNOWN = 0; + + /** + * The requested key was not found when trying to perform a decrypt + * operation. + * <p> + * The operation can be retried after adding the correct decryption key. + */ + public static final int ERROR_NO_KEY = 1; + + /** + * The key used for decryption is no longer valid due to license term + * expiration. + * <p> + * The operation can be retried after updating the expired keys. + */ + public static final int ERROR_KEY_EXPIRED = 2; + + /** + * A required crypto resource was not able to be allocated while + * attempting the requested operation. + * <p> + * The operation can be retried if the app is able to release resources. + */ + public static final int ERROR_RESOURCE_BUSY = 3; + + /** + * The output protection levels supported by the device are not + * sufficient to meet the requirements set by the content owner in the + * license policy. + */ + public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; + + /** + * Decryption was attempted on a session that is not opened, which could + * be due to a failure to open the session, closing the session + * prematurely, the session being reclaimed by the resource manager, or + * a non-existent session id. + */ + public static final int ERROR_SESSION_NOT_OPENED = 5; + + /** + * An operation was attempted that could not be supported by the crypto + * system of the device in its current configuration. + * <p> + * This may occur when the license policy requires device security + * features that aren't supported by the device, or due to an internal + * error in the crypto system that prevents the specified security + * policy from being met. + */ + public static final int ERROR_UNSUPPORTED_OPERATION = 6; + + /** + * The security level of the device is not sufficient to meet the + * requirements set by the content owner in the license policy. + */ + public static final int ERROR_INSUFFICIENT_SECURITY = 7; + + /** + * The video frame being decrypted exceeds the size of the device's + * protected output buffers. + * <p> + * When encountering this error the app should try playing content + * of a lower resolution or skipping the problematic frame. + */ + public static final int ERROR_FRAME_TOO_LARGE = 8; + + /** + * The session state has been invalidated. This can occur on devices + * that are not capable of retaining crypto session state across device + * suspend/resume. + * <p> + * The session must be closed and a new session opened to resume + * operation. + */ + public static final int ERROR_LOST_STATE = 9; + + /** + * Certificate is malformed or is of the wrong type. + * <p> + * Ensure the certificate provided by the app or returned from the + * license server is valid. Check with the {@link MediaDrm} plugin + * vendor for the expected certificate format. + */ + public static final int ERROR_CERTIFICATE_MALFORMED = 10; + + /** + * Certificate has not been set. + * <p> + * Ensure the certificate has been provided by the app. Check with the + * {@link MediaDrm} plugin vendor for the expected method to provide + * {@link MediaDrm} a certificate. + */ + public static final int ERROR_CERTIFICATE_MISSING = 11; + + /** + * An error happened within the crypto library used by the drm plugin. + */ + public static final int ERROR_CRYPTO_LIBRARY = 12; + + /** + * Unexpected error reported by the device OEM subsystem. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_GENERIC_OEM = 13; + + /** + * Unexpected internal failure in {@link MediaDrm}/{@link MediaCrypto}. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_GENERIC_PLUGIN = 14; + + /** + * The init data parameter passed to {@link MediaDrm#getKeyRequest} is + * empty or invalid. + * <p> + * Init data is typically obtained from {@link + * MediaExtractor#getPsshInfo()} or {@link + * MediaExtractor#getDrmInitData()}. Check with the {@link MediaDrm} + * plugin vendor for the expected init data format. + */ + public static final int ERROR_INIT_DATA = 15; + + /** + * Either the key was not loaded from the license before attempting the + * operation, or the key ID parameter provided by the app is incorrect. + * <p> + * Ensure the proper keys are in the license, and check the key ID + * parameter provided by the app is correct. Check with the {@link + * MediaDrm} plugin vendor for the expected license format. + */ + public static final int ERROR_KEY_NOT_LOADED = 16; + + /** + * The license response was empty, fields are missing or otherwise + * unable to be parsed or decrypted. + * <p> + * Check for mistakes such as empty or overwritten buffers. Otherwise, + * check with the {@link MediaDrm} plugin vendor for the expected + * license format. + */ + public static final int ERROR_LICENSE_PARSE = 17; + + /** + * The operation (e.g. to renew or persist a license) is prohibited by + * the license policy. + * <p> + * Check the license policy configuration on the license server. + */ + public static final int ERROR_LICENSE_POLICY = 18; + + /** + * Failed to generate a release request because a field in the offline + * license is empty or malformed. + * <p> + * The license can't be released on the server, but the app may remove + * the offline license explicitly using {@link + * MediaDrm#removeOfflineLicense}. + */ + public static final int ERROR_LICENSE_RELEASE = 19; + + /** + * The license server detected an error in the license request. + * <p> + * Check for errors on the license server. + */ + public static final int ERROR_LICENSE_REQUEST_REJECTED = 20; + + /** + * Failed to restore an offline license because a field in the offline + * license is empty or malformed. + * <p> + * Try requesting the license again if the device is online. + */ + public static final int ERROR_LICENSE_RESTORE = 21; + + /** + * Offline license is in an invalid state for the attempted operation. + * <p> + * Check the sequence of API calls made that can affect offline license + * state. For example, this could happen when the app attempts to + * restore a license after it has been released. + */ + public static final int ERROR_LICENSE_STATE = 22; + + /** + * Failure in the media framework. + * <p> + * Try releasing media resources (e.g. {@link MediaCodec}, {@link + * MediaDrm}), and restarting playback. + */ + public static final int ERROR_MEDIA_FRAMEWORK = 23; + + /** + * Error loading the provisioned certificate. + * <p> + * Re-provisioning may resolve the problem; check with the {@link + * MediaDrm} plugin vendor for re-provisioning instructions. Otherwise, + * using a different security level may resolve the issue. + */ + public static final int ERROR_PROVISIONING_CERTIFICATE = 24; + + /** + * Required steps were not performed before provisioning was attempted. + * <p> + * Ask the {@link MediaDrm} plugin vendor for situations where this + * error may occur. + */ + public static final int ERROR_PROVISIONING_CONFIG = 25; + + /** + * The provisioning response was empty, fields are missing or otherwise + * unable to be parsed. + * <p> + * Check for mistakes such as empty or overwritten buffers. Otherwise, + * check with the {@link MediaDrm} plugin vendor for the expected + * provisioning response format. + */ + public static final int ERROR_PROVISIONING_PARSE = 26; + + /** + * Provisioning failed in a way that is likely to succeed on a + * subsequent attempt. + * <p> + * The app should retry the operation. + */ + public static final int ERROR_PROVISIONING_RETRY = 27; + + /** + * This indicates that apps using MediaDrm sessions are + * temporarily exceeding the capacity of available crypto + * resources. + * <p> + * The app should retry the operation later. + */ + public static final int ERROR_RESOURCE_CONTENTION = 28; + + /** + * Failed to generate a secure stop request because a field in the + * stored license is empty or malformed. + * <p> + * The secure stop can't be released on the server, but the app may + * remove it explicitly using {@link MediaDrm#removeSecureStop}. + */ + public static final int ERROR_SECURE_STOP_RELEASE = 29; + + /** + * The plugin was unable to read data from the filesystem. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_STORAGE_READ = 30; + + /** + * The plugin was unable to write data to the filesystem. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_STORAGE_WRITE = 31; + + /** + * {@link MediaCodec#queueSecureInputBuffer} called with 0 subsamples. + * <p> + * Check the {@link MediaCodec.CryptoInfo} object passed to {@link + * MediaCodec#queueSecureInputBuffer}. + */ + public static final int ERROR_ZERO_SUBSAMPLES = 32; + + } + + /** @hide */ + @IntDef({ + ErrorCodes.ERROR_NO_KEY, + ErrorCodes.ERROR_KEY_EXPIRED, + ErrorCodes.ERROR_RESOURCE_BUSY, + ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION, + ErrorCodes.ERROR_SESSION_NOT_OPENED, + ErrorCodes.ERROR_UNSUPPORTED_OPERATION, + ErrorCodes.ERROR_INSUFFICIENT_SECURITY, + ErrorCodes.ERROR_FRAME_TOO_LARGE, + ErrorCodes.ERROR_LOST_STATE, + ErrorCodes.ERROR_CERTIFICATE_MALFORMED, + ErrorCodes.ERROR_CERTIFICATE_MISSING, + ErrorCodes.ERROR_CRYPTO_LIBRARY, + ErrorCodes.ERROR_GENERIC_OEM, + ErrorCodes.ERROR_GENERIC_PLUGIN, + ErrorCodes.ERROR_INIT_DATA, + ErrorCodes.ERROR_KEY_NOT_LOADED, + ErrorCodes.ERROR_LICENSE_PARSE, + ErrorCodes.ERROR_LICENSE_POLICY, + ErrorCodes.ERROR_LICENSE_RELEASE, + ErrorCodes.ERROR_LICENSE_REQUEST_REJECTED, + ErrorCodes.ERROR_LICENSE_RESTORE, + ErrorCodes.ERROR_LICENSE_STATE, + ErrorCodes.ERROR_MEDIA_FRAMEWORK, + ErrorCodes.ERROR_PROVISIONING_CERTIFICATE, + ErrorCodes.ERROR_PROVISIONING_CONFIG, + ErrorCodes.ERROR_PROVISIONING_PARSE, + ErrorCodes.ERROR_PROVISIONING_RETRY, + ErrorCodes.ERROR_SECURE_STOP_RELEASE, + ErrorCodes.ERROR_STORAGE_READ, + ErrorCodes.ERROR_STORAGE_WRITE, + ErrorCodes.ERROR_ZERO_SUBSAMPLES + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MediaDrmErrorCode {} + + /** + * Thrown when a general failure occurs during a MediaDrm operation. + * Extends {@link IllegalStateException} with the addition of an error * code that may be useful in diagnosing the failure. + * <p> + * Please refer to {@link ErrorCodes} for the general error handling + * strategy and details about each possible return value from {@link + * MediaDrmStateException#getErrorCode()}. */ public static final class MediaDrmStateException extends java.lang.IllegalStateException { private final int mErrorCode; @@ -311,15 +674,30 @@ public final class MediaDrm implements AutoCloseable { } /** - * Retrieve the associated error code + * Returns error code associated with this {@link + * MediaDrmStateException}. + * <p> + * Please refer to {@link ErrorCodes} for the general error handling + * strategy and details about each possible return value. * - * @hide + * @return an error code defined in {@link MediaDrm.ErrorCodes}. */ + @MediaDrmErrorCode public int getErrorCode() { return mErrorCode; } /** + * Returns true if the {@link MediaDrmStateException} is a transient + * issue, perhaps due to resource constraints, and that the operation + * (e.g. provisioning) may succeed on a subsequent attempt. + */ + public boolean isTransient() { + return mErrorCode == ErrorCodes.ERROR_PROVISIONING_RETRY + || mErrorCode == ErrorCodes.ERROR_RESOURCE_CONTENTION; + } + + /** * Retrieve a developer-readable diagnostic information string * associated with the exception. Do not show this to end-users, * since this string will not be localized or generally comprehensible @@ -332,7 +710,13 @@ public final class MediaDrm implements AutoCloseable { } /** - * Thrown when an error occurs in any method that has a session context. + * {@link SessionException} is a misnomer because it may occur in methods + * <b>without</b> a session context. + * <p> + * A {@link SessionException} is most likely to be thrown when an operation + * failed in a way that is likely to succeed on a subsequent attempt; call + * {@link #isTransient()} to determine whether the app should retry the + * failing operation. */ public static final class SessionException extends RuntimeException { public SessionException(int errorCode, @Nullable String detailMessage) { @@ -342,6 +726,7 @@ public final class MediaDrm implements AutoCloseable { /** * The SessionException has an unknown error code. + * @deprecated Unused. */ public static final int ERROR_UNKNOWN = 0; @@ -349,6 +734,10 @@ public final class MediaDrm implements AutoCloseable { * This indicates that apps using MediaDrm sessions are * temporarily exceeding the capacity of available crypto * resources. The app should retry the operation later. + * + * @deprecated Please use {@link #isTransient()} instead of comparing + * the return value of {@link #getErrorCode()} against + * {@link SessionException#ERROR_RESOURCE_CONTENTION}. */ public static final int ERROR_RESOURCE_CONTENTION = 1; @@ -361,12 +750,26 @@ public final class MediaDrm implements AutoCloseable { /** * Retrieve the error code associated with the SessionException + * + * @deprecated Please use {@link #isTransient()} instead of comparing + * the return value of {@link #getErrorCode()} against + * {@link SessionException#ERROR_RESOURCE_CONTENTION}. */ @SessionErrorCode public int getErrorCode() { return mErrorCode; } + /** + * Returns true if the {@link SessionException} is a transient + * issue, perhaps due to resource constraints, and that the operation + * (e.g. provisioning, generating requests) may succeed on a subsequent + * attempt. + */ + public boolean isTransient() { + return mErrorCode == ERROR_RESOURCE_CONTENTION; + } + private final int mErrorCode; } @@ -1144,12 +1547,78 @@ public final class MediaDrm implements AutoCloseable { * problem with the certifcate */ @NonNull - public native KeyRequest getKeyRequest( + public KeyRequest getKeyRequest( @NonNull byte[] scope, @Nullable byte[] init, @Nullable String mimeType, @KeyType int keyType, @Nullable HashMap<String, String> optionalParameters) - throws NotProvisionedException; + throws NotProvisionedException { + HashMap<String, String> internalParams; + if (optionalParameters == null) { + internalParams = new HashMap<>(); + } else { + internalParams = new HashMap<>(optionalParameters); + } + byte[] rawBytes = getNewestAvailablePackageCertificateRawBytes(); + byte[] hashBytes = null; + if (rawBytes != null) { + hashBytes = getDigestBytes(rawBytes, "SHA-256"); + } + if (hashBytes != null) { + Base64.Encoder encoderB64 = Base64.getEncoder(); + String hashBytesB64 = encoderB64.encodeToString(hashBytes); + internalParams.put("package_certificate_hash_bytes", hashBytesB64); + } + return getKeyRequestNative(scope, init, mimeType, keyType, internalParams); + } + + @Nullable + private byte[] getNewestAvailablePackageCertificateRawBytes() { + Application application = ActivityThread.currentApplication(); + if (application == null) { + Log.w(TAG, "pkg cert: Application is null"); + return null; + } + PackageManager pm = application.getPackageManager(); + if (pm == null) { + Log.w(TAG, "pkg cert: PackageManager is null"); + return null; + } + PackageInfo packageInfo = null; + try { + packageInfo = pm.getPackageInfo(mAppPackageName, + PackageManager.GET_SIGNING_CERTIFICATES); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, mAppPackageName, e); + } + if (packageInfo == null || packageInfo.signingInfo == null) { + Log.w(TAG, "pkg cert: PackageInfo or SigningInfo is null"); + return null; + } + Signature[] signers = packageInfo.signingInfo.getApkContentsSigners(); + if (signers != null && signers.length == 1) { + return signers[0].toByteArray(); + } + Log.w(TAG, "pkg cert: " + signers.length + " signers"); + return null; + } + + @Nullable + private static byte[] getDigestBytes(@NonNull byte[] rawBytes, @NonNull String algorithm) { + try { + MessageDigest messageDigest = MessageDigest.getInstance(algorithm); + return messageDigest.digest(rawBytes); + } catch (NoSuchAlgorithmException e) { + Log.w(TAG, algorithm, e); + } + return null; + } + @NonNull + private native KeyRequest getKeyRequestNative( + @NonNull byte[] scope, @Nullable byte[] init, + @Nullable String mimeType, @KeyType int keyType, + @Nullable HashMap<String, String> optionalParameters) + throws NotProvisionedException; /** * A key response is received from the license server by the app, then it is diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 740bc2dbeb43..c0185dcc4539 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -2525,7 +2525,9 @@ public final class TvInputManager { /** * Pauses TV program recording in the current recording session. * - * @param params A set of extra parameters which might be handled with this event. + * @param params Domain-specific data for this request. Keys <em>must</em> be a scoped + * name, i.e. prefixed with a package name you own, so that different developers + * will not create conflicting keys. * {@link TvRecordingClient#pauseRecording(Bundle)}. */ void pauseRecording(@NonNull Bundle params) { @@ -2543,7 +2545,9 @@ public final class TvInputManager { /** * Resumes TV program recording in the current recording session. * - * @param params A set of extra parameters which might be handled with this event. + * @param params Domain-specific data for this request. Keys <em>must</em> be a scoped + * name, i.e. prefixed with a package name you own, so that different developers + * will not create conflicting keys. * {@link TvRecordingClient#resumeRecording(Bundle)}. */ void resumeRecording(@NonNull Bundle params) { diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 22c3572e963b..6f1b6d3ba7b5 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -343,11 +343,56 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, } } +jint MediaErrorToJavaError(status_t err) { +#define STATUS_CASE(status) \ + case status: \ + return J##status + + switch (err) { + STATUS_CASE(ERROR_DRM_UNKNOWN); + STATUS_CASE(ERROR_DRM_NO_LICENSE); + STATUS_CASE(ERROR_DRM_LICENSE_EXPIRED); + STATUS_CASE(ERROR_DRM_RESOURCE_BUSY); + STATUS_CASE(ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION); + STATUS_CASE(ERROR_DRM_SESSION_NOT_OPENED); + STATUS_CASE(ERROR_DRM_CANNOT_HANDLE); + STATUS_CASE(ERROR_DRM_INSUFFICIENT_SECURITY); + STATUS_CASE(ERROR_DRM_FRAME_TOO_LARGE); + STATUS_CASE(ERROR_DRM_SESSION_LOST_STATE); + STATUS_CASE(ERROR_DRM_CERTIFICATE_MALFORMED); + STATUS_CASE(ERROR_DRM_CERTIFICATE_MISSING); + STATUS_CASE(ERROR_DRM_CRYPTO_LIBRARY); + STATUS_CASE(ERROR_DRM_GENERIC_OEM); + STATUS_CASE(ERROR_DRM_GENERIC_PLUGIN); + STATUS_CASE(ERROR_DRM_INIT_DATA); + STATUS_CASE(ERROR_DRM_KEY_NOT_LOADED); + STATUS_CASE(ERROR_DRM_LICENSE_PARSE); + STATUS_CASE(ERROR_DRM_LICENSE_POLICY); + STATUS_CASE(ERROR_DRM_LICENSE_RELEASE); + STATUS_CASE(ERROR_DRM_LICENSE_REQUEST_REJECTED); + STATUS_CASE(ERROR_DRM_LICENSE_RESTORE); + STATUS_CASE(ERROR_DRM_LICENSE_STATE); + STATUS_CASE(ERROR_DRM_MEDIA_FRAMEWORK); + STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE); + STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG); + STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE); + STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY); + STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION); + STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE); + STATUS_CASE(ERROR_DRM_STORAGE_READ); + STATUS_CASE(ERROR_DRM_STORAGE_WRITE); + STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES); +#undef STATUS_CASE + } + return static_cast<jint>(err); +} + static void throwStateException(JNIEnv *env, const char *msg, status_t err) { ALOGE("Illegal state exception: %s (%d)", msg, err); + jint jerr = MediaErrorToJavaError(err); jobject exception = env->NewObject(gFields.stateException.classId, - gFields.stateException.init, static_cast<int>(err), + gFields.stateException.init, static_cast<int>(jerr), env->NewStringUTF(msg)); env->Throw(static_cast<jthrowable>(exception)); } @@ -2056,7 +2101,7 @@ static const JNINativeMethod gMethods[] = { { "closeSessionNative", "([B)V", (void *)android_media_MediaDrm_closeSession }, - { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)" + { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)" "Landroid/media/MediaDrm$KeyRequest;", (void *)android_media_MediaDrm_getKeyRequest }, diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h index b1f544cb2dbe..dc0793af2d17 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -28,6 +28,44 @@ namespace { +enum { + // TODO(b/180483929): use reverse jni e.g. android_media_MediaDrm_native_init + // KEEP IN SYNC with MediaDrm$ErrorCodes in MediaDrm.java! + JERROR_DRM_UNKNOWN = 0, + JERROR_DRM_NO_LICENSE = 1, + JERROR_DRM_LICENSE_EXPIRED = 2, + JERROR_DRM_RESOURCE_BUSY = 3, + JERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 4, + JERROR_DRM_SESSION_NOT_OPENED = 5, + JERROR_DRM_CANNOT_HANDLE = 6, + JERROR_DRM_INSUFFICIENT_SECURITY = 7, + JERROR_DRM_FRAME_TOO_LARGE = 8, + JERROR_DRM_SESSION_LOST_STATE = 9, + JERROR_DRM_CERTIFICATE_MALFORMED = 10, + JERROR_DRM_CERTIFICATE_MISSING = 11, + JERROR_DRM_CRYPTO_LIBRARY = 12, + JERROR_DRM_GENERIC_OEM = 13, + JERROR_DRM_GENERIC_PLUGIN = 14, + JERROR_DRM_INIT_DATA = 15, + JERROR_DRM_KEY_NOT_LOADED = 16, + JERROR_DRM_LICENSE_PARSE = 17, + JERROR_DRM_LICENSE_POLICY = 18, + JERROR_DRM_LICENSE_RELEASE = 19, + JERROR_DRM_LICENSE_REQUEST_REJECTED = 20, + JERROR_DRM_LICENSE_RESTORE = 21, + JERROR_DRM_LICENSE_STATE = 22, + JERROR_DRM_MEDIA_FRAMEWORK = 23, + JERROR_DRM_PROVISIONING_CERTIFICATE = 24, + JERROR_DRM_PROVISIONING_CONFIG = 25, + JERROR_DRM_PROVISIONING_PARSE = 26, + JERROR_DRM_PROVISIONING_RETRY = 27, + JERROR_DRM_RESOURCE_CONTENTION = 28, + JERROR_DRM_SECURE_STOP_RELEASE = 29, + JERROR_DRM_STORAGE_READ = 30, + JERROR_DRM_STORAGE_WRITE = 31, + JERROR_DRM_ZERO_SUBSAMPLES = 32, +}; + struct ListenerArgs { jbyteArray jSessionId; jbyteArray jData; @@ -98,6 +136,8 @@ private: DISALLOW_EVIL_CONSTRUCTORS(JDrm); }; +jint MediaErrorToJavaError(status_t err); + } // namespace android #endif // _ANDROID_MEDIA_DRM_H_ diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index a1fd7eefaf9a..e427981b87d7 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -4780,17 +4780,23 @@ public class SettingsProvider extends ContentProvider { } if (currentVersion == 192) { - // Version 192: set the default value for magnification capabilities. If - // magnification is enabled by the user, set it to full-screen, and set a value - // to show a prompt when using the magnification first time after upgrading. + // Version 192: set the default value for magnification capabilities. + // If the device supports magnification area and magnification is enabled + // by the user, set it to full-screen, and set a value to show a prompt + // when using the magnification first time after upgrading. final SettingsState secureSettings = getSecureSettingsLocked(userId); final Setting magnificationCapabilities = secureSettings.getSettingLocked( Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY); + final boolean supportMagnificationArea = getContext().getResources().getBoolean( + com.android.internal.R.bool.config_magnification_area); + final int capability = supportMagnificationArea + ? R.integer.def_accessibility_magnification_capabilities + : Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; + final String supportShowPrompt = supportMagnificationArea ? "1" : "0"; if (magnificationCapabilities.isNull()) { secureSettings.insertSettingLocked( Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY, - String.valueOf(getContext().getResources().getInteger( - R.integer.def_accessibility_magnification_capabilities)), + String.valueOf(getContext().getResources().getInteger(capability)), null, true, SettingsState.SYSTEM_PACKAGE_NAME); if (isMagnificationSettingsOn(secureSettings)) { @@ -4800,7 +4806,8 @@ public class SettingsProvider extends ContentProvider { null, false /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME); secureSettings.insertSettingLocked( - Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT, "1", + Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT, + supportShowPrompt, null, false /* makeDefault */, SettingsState.SYSTEM_PACKAGE_NAME); } diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml deleted file mode 100644 index 2b33e17a5fbd..000000000000 --- a/packages/SystemUI/res/layout/pip_menu_activity.xml +++ /dev/null @@ -1,93 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2016 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/background" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <!-- Menu layout --> - <FrameLayout - android:id="@+id/menu_container" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:forceHasOverlappingRendering="false" - android:accessibilityTraversalAfter="@id/dismiss"> - - <!-- The margins for this container is calculated in the code depending on whether the - actions_container is visible. --> - <FrameLayout - android:id="@+id/expand_container" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <ImageButton - android:id="@+id/expand_button" - android:layout_width="60dp" - android:layout_height="60dp" - android:layout_gravity="center" - android:contentDescription="@string/pip_phone_expand" - android:padding="10dp" - android:src="@drawable/pip_expand" - android:background="?android:selectableItemBackgroundBorderless" /> - </FrameLayout> - - <FrameLayout - android:id="@+id/actions_container" - android:layout_width="match_parent" - android:layout_height="@dimen/pip_action_size" - android:layout_gravity="bottom" - android:visibility="invisible"> - <LinearLayout - android:id="@+id/actions_group" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="center_horizontal" - android:orientation="horizontal" - android:divider="@android:color/transparent" - android:showDividers="middle" /> - </FrameLayout> - </FrameLayout> - - <ImageButton - android:id="@+id/settings" - android:layout_width="@dimen/pip_action_size" - android:layout_height="@dimen/pip_action_size" - android:layout_gravity="top|start" - android:padding="@dimen/pip_action_padding" - android:contentDescription="@string/pip_phone_settings" - android:src="@drawable/ic_settings" - android:background="?android:selectableItemBackgroundBorderless" /> - - <ImageButton - android:id="@+id/dismiss" - android:layout_width="@dimen/pip_action_size" - android:layout_height="@dimen/pip_action_size" - android:layout_gravity="top|end" - android:padding="@dimen/pip_action_padding" - android:contentDescription="@string/pip_phone_close" - android:src="@drawable/ic_close_white" - android:background="?android:selectableItemBackgroundBorderless" /> - - <!--TODO (b/156917828): Add content description for a11y purposes?--> - <ImageButton - android:id="@+id/resize_handle" - android:layout_width="@dimen/pip_resize_handle_size" - android:layout_height="@dimen/pip_resize_handle_size" - android:layout_gravity="top|start" - android:layout_margin="@dimen/pip_resize_handle_margin" - android:src="@drawable/pip_resize_handle" - android:background="?android:selectableItemBackgroundBorderless" /> -</FrameLayout> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index f6b239e31e99..ebb6e30d4b3b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -254,6 +254,7 @@ public class Task { public Task(Task other) { this(other.key, other.colorPrimary, other.colorBackground, other.isDockable, other.isLocked, other.taskDescription, other.topActivity); + lastSnapshotData.set(other.lastSnapshotData); } /** @@ -281,6 +282,25 @@ public class Task { : key.baseIntent.getComponent(); } + public void setLastSnapshotData(ActivityManager.RecentTaskInfo rawTask) { + lastSnapshotData.set(rawTask.lastSnapshotData); + } + + /** + * Returns the visible width to height ratio. Returns 0f if snapshot data is not available. + */ + public float getVisibleThumbnailRatio() { + if (lastSnapshotData.taskSize == null || lastSnapshotData.contentInsets == null) { + return 0f; + } + + float availableWidth = lastSnapshotData.taskSize.x - (lastSnapshotData.contentInsets.left + + lastSnapshotData.contentInsets.right); + float availableHeight = lastSnapshotData.taskSize.y - (lastSnapshotData.contentInsets.top + + lastSnapshotData.contentInsets.bottom); + return availableWidth / availableHeight; + } + @Override public boolean equals(Object o) { // Check that the id matches diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java index 6c77af7bbddd..c5d54391959a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java @@ -100,4 +100,10 @@ public abstract class TaskStackChangeListener { /** @see ITaskStackListener#onActivityRotation(int)*/ public void onActivityRotation(int displayId) { } + + /** + * Called when the lock task mode changes. See ActivityManager#LOCK_TASK_MODE_* and + * LockTaskController. + */ + public void onLockTaskModeChanged(int mode) { } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java index 8f08f5a51143..d2698ee9fe3b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java @@ -93,6 +93,7 @@ public class TaskStackChangeListeners { private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 20; private static final int ON_TASK_DESCRIPTION_CHANGED = 21; private static final int ON_ACTIVITY_ROTATION = 22; + private static final int ON_LOCK_TASK_MODE_CHANGED = 23; /** * List of {@link TaskStackChangeListener} registered from {@link #addListener}. @@ -273,6 +274,11 @@ public class TaskStackChangeListeners { } @Override + public void onLockTaskModeChanged(int mode) { + mHandler.obtainMessage(ON_LOCK_TASK_MODE_CHANGED, mode, 0 /* unused */).sendToTarget(); + } + + @Override public boolean handleMessage(Message msg) { synchronized (mTaskStackListeners) { switch (msg.what) { @@ -421,6 +427,12 @@ public class TaskStackChangeListeners { } break; } + case ON_LOCK_TASK_MODE_CHANGED: { + for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { + mTaskStackListeners.get(i).onLockTaskModeChanged(msg.arg1); + } + break; + } } } if (msg.obj instanceof SomeArgs) { diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierText.java b/packages/SystemUI/src/com/android/keyguard/CarrierText.java index e4f6e131258e..f6b03c1fa013 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierText.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierText.java @@ -24,14 +24,41 @@ import android.util.AttributeSet; import android.view.View; import android.widget.TextView; +import com.android.systemui.Dependency; import com.android.systemui.R; import java.util.Locale; public class CarrierText extends TextView { - private final boolean mShowMissingSim; + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final String TAG = "CarrierText"; - private final boolean mShowAirplaneMode; + private static CharSequence mSeparator; + + private boolean mShowMissingSim; + + private boolean mShowAirplaneMode; + private boolean mShouldMarquee; + + private CarrierTextController mCarrierTextController; + + private CarrierTextController.CarrierTextCallback mCarrierTextCallback = + new CarrierTextController.CarrierTextCallback() { + @Override + public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { + setText(info.carrierText); + } + + @Override + public void startedGoingToSleep() { + setSelected(false); + } + + @Override + public void finishedWakingUp() { + setSelected(true); + } + }; public CarrierText(Context context) { this(context, null); @@ -51,6 +78,30 @@ public class CarrierText extends TextView { } setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps)); } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mSeparator = getResources().getString( + com.android.internal.R.string.kg_text_message_separator); + mCarrierTextController = new CarrierTextController(mContext, mSeparator, mShowAirplaneMode, + mShowMissingSim); + mShouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive(); + setSelected(mShouldMarquee); // Allow marquee to work. + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mCarrierTextController.setListening(mCarrierTextCallback); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mCarrierTextController.setListening(null); + } + @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); @@ -62,15 +113,7 @@ public class CarrierText extends TextView { } } - public boolean getShowAirplaneMode() { - return mShowAirplaneMode; - } - - public boolean getShowMissingSim() { - return mShowMissingSim; - } - - private static class CarrierTextTransformationMethod extends SingleLineTransformationMethod { + private class CarrierTextTransformationMethod extends SingleLineTransformationMethod { private final Locale mLocale; private final boolean mAllCaps; diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 46a6d8b82911..b1e14346c3fa 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,61 +16,680 @@ package com.android.keyguard; -import com.android.systemui.util.ViewController; +import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.settingslib.WirelessUtils; +import com.android.systemui.Dependency; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.keyguard.WakefulnessLifecycle; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import javax.inject.Inject; /** - * Controller for {@link CarrierText}. + * Controller that generates text including the carrier names and/or the status of all the SIM + * interfaces in the device. Through a callback, the updates can be retrieved either as a list or + * separated by a given separator {@link CharSequence}. */ -public class CarrierTextController extends ViewController<CarrierText> { - private final CarrierTextManager mCarrierTextManager; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; +public class CarrierTextController { + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final String TAG = "CarrierTextController"; - private final CarrierTextManager.CarrierTextCallback mCarrierTextCallback = - new CarrierTextManager.CarrierTextCallback() { + private final boolean mIsEmergencyCallCapable; + private final Handler mMainHandler; + private final Handler mBgHandler; + private boolean mTelephonyCapable; + private boolean mShowMissingSim; + private boolean mShowAirplaneMode; + private final AtomicBoolean mNetworkSupported = new AtomicBoolean(); + @VisibleForTesting + protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private WifiManager mWifiManager; + private boolean[] mSimErrorState; + private final int mSimSlotsNumber; + @Nullable // Check for nullability before dispatching + private CarrierTextCallback mCarrierTextCallback; + private Context mContext; + private CharSequence mSeparator; + private WakefulnessLifecycle mWakefulnessLifecycle; + private final WakefulnessLifecycle.Observer mWakefulnessObserver = + new WakefulnessLifecycle.Observer() { @Override - public void updateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { - mView.setText(info.carrierText); + public void onFinishedWakingUp() { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) callback.finishedWakingUp(); } @Override - public void startedGoingToSleep() { - mView.setSelected(false); + public void onStartedGoingToSleep() { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) callback.startedGoingToSleep(); } + }; - @Override - public void finishedWakingUp() { - mView.setSelected(true); + @VisibleForTesting + protected final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onRefreshCarrierInfo() { + if (DEBUG) { + Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: " + + Boolean.toString(mTelephonyCapable)); + } + updateCarrierText(); + } + + @Override + public void onTelephonyCapable(boolean capable) { + if (DEBUG) { + Log.d(TAG, "onTelephonyCapable() mTelephonyCapable: " + + Boolean.toString(capable)); + } + mTelephonyCapable = capable; + updateCarrierText(); + } + + public void onSimStateChanged(int subId, int slotId, int simState) { + if (slotId < 0 || slotId >= mSimSlotsNumber) { + Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId + + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable)); + return; + } + + if (DEBUG) Log.d(TAG, "onSimStateChanged: " + getStatusForIccState(simState)); + if (getStatusForIccState(simState) == CarrierTextController.StatusMode.SimIoError) { + mSimErrorState[slotId] = true; + updateCarrierText(); + } else if (mSimErrorState[slotId]) { + mSimErrorState[slotId] = false; + updateCarrierText(); + } + } + }; + + private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveMobileDataSubscription = subId; + if (mNetworkSupported.get() && mCarrierTextCallback != null) { + updateCarrierText(); + } + } + }; + + /** + * The status of this lock screen. Primarily used for widgets on LockScreen. + */ + private enum StatusMode { + Normal, // Normal case (sim card present, it's not locked) + NetworkLocked, // SIM card is 'network locked'. + SimMissing, // SIM card is missing. + SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access + SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times + SimLocked, // SIM card is currently locked + SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure + SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM. + SimIoError, // SIM card is faulty + SimUnknown // SIM card is unknown + } + + /** + * Controller that provides updates on text with carriers names or SIM status. + * Used by {@link CarrierText}. + * + * @param separator Separator between different parts of the text + */ + public CarrierTextController(Context context, CharSequence separator, boolean showAirplaneMode, + boolean showMissingSim) { + mContext = context; + mIsEmergencyCallCapable = getTelephonyManager().isVoiceCapable(); + + mShowAirplaneMode = showAirplaneMode; + mShowMissingSim = showMissingSim; + + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + mSeparator = separator; + mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class); + mSimSlotsNumber = getTelephonyManager().getSupportedModemCount(); + mSimErrorState = new boolean[mSimSlotsNumber]; + mMainHandler = Dependency.get(Dependency.MAIN_HANDLER); + mBgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER)); + mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); + mBgHandler.post(() -> { + boolean supported = ConnectivityManager.from(mContext).isNetworkSupported( + ConnectivityManager.TYPE_MOBILE); + if (supported && mNetworkSupported.compareAndSet(false, supported)) { + // This will set/remove the listeners appropriately. Note that it will never double + // add the listeners. + handleSetListening(mCarrierTextCallback); + } + }); + } + + private TelephonyManager getTelephonyManager() { + return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + } + + /** + * Checks if there are faulty cards. Adds the text depending on the slot of the card + * + * @param text: current carrier text based on the sim state + * @param carrierNames names order by subscription order + * @param subOrderBySlot array containing the sub index for each slot ID + * @param noSims: whether a valid sim card is inserted + * @return text + */ + private CharSequence updateCarrierTextWithSimIoError(CharSequence text, + CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { + final CharSequence carrier = ""; + CharSequence carrierTextForSimIOError = getCarrierTextForSimState( + TelephonyManager.SIM_STATE_CARD_IO_ERROR, carrier); + // mSimErrorState has the state of each sim indexed by slotID. + for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) { + if (!mSimErrorState[index]) { + continue; + } + // In the case when no sim cards are detected but a faulty card is inserted + // overwrite the text and only show "Invalid card" + if (noSims) { + return concatenate(carrierTextForSimIOError, + getContext().getText( + com.android.internal.R.string.emergency_calls_only), + mSeparator); + } else if (subOrderBySlot[index] != -1) { + int subIndex = subOrderBySlot[index]; + // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 + carrierNames[subIndex] = concatenate(carrierTextForSimIOError, + carrierNames[subIndex], + mSeparator); + } else { + // concatenate "Invalid card" when faulty card is inserted in other slot + text = concatenate(text, carrierTextForSimIOError, mSeparator); + } + + } + return text; + } + + /** + * This may be called internally after retrieving the correct value of {@code mNetworkSupported} + * (assumed false to start). In that case, the following happens: + * <ul> + * <li> If there was a registered callback, and the network is supported, it will register + * listeners. + * <li> If there was not a registered callback, it will try to remove unregistered listeners + * which is a no-op + * </ul> + * + * This call will always be processed in a background thread. + */ + private void handleSetListening(CarrierTextCallback callback) { + TelephonyManager telephonyManager = getTelephonyManager(); + if (callback != null) { + mCarrierTextCallback = callback; + if (mNetworkSupported.get()) { + // Keyguard update monitor expects callbacks from main thread + mMainHandler.post(() -> mKeyguardUpdateMonitor.registerCallback(mCallback)); + mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + telephonyManager.listen(mPhoneStateListener, + LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + } else { + // Don't listen and clear out the text when the device isn't a phone. + mMainHandler.post(() -> callback.updateCarrierInfo( + new CarrierTextCallbackInfo("", null, false, null) + )); + } + } else { + mCarrierTextCallback = null; + mMainHandler.post(() -> mKeyguardUpdateMonitor.removeCallback(mCallback)); + mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); + telephonyManager.listen(mPhoneStateListener, LISTEN_NONE); + } + } + + /** + * Sets the listening status of this controller. If the callback is null, it is set to + * not listening. + * + * @param callback Callback to provide text updates + */ + public void setListening(CarrierTextCallback callback) { + mBgHandler.post(() -> handleSetListening(callback)); + } + + protected List<SubscriptionInfo> getSubscriptionInfo() { + return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); + } + + protected void updateCarrierText() { + boolean allSimsMissing = true; + boolean anySimReadyAndInService = false; + CharSequence displayText = null; + List<SubscriptionInfo> subs = getSubscriptionInfo(); + + final int numSubs = subs.size(); + final int[] subsIds = new int[numSubs]; + // This array will contain in position i, the index of subscription in slot ID i. + // -1 if no subscription in that slot + final int[] subOrderBySlot = new int[mSimSlotsNumber]; + for (int i = 0; i < mSimSlotsNumber; i++) { + subOrderBySlot[i] = -1; + } + final CharSequence[] carrierNames = new CharSequence[numSubs]; + if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); + + for (int i = 0; i < numSubs; i++) { + int subId = subs.get(i).getSubscriptionId(); + carrierNames[i] = ""; + subsIds[i] = subId; + subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; + int simState = mKeyguardUpdateMonitor.getSimState(subId); + CharSequence carrierName = subs.get(i).getCarrierName(); + CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName); + if (DEBUG) { + Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName); + } + if (carrierTextForSimState != null) { + allSimsMissing = false; + carrierNames[i] = carrierTextForSimState; + } + if (simState == TelephonyManager.SIM_STATE_READY) { + ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); + if (ss != null && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) { + // hack for WFC (IWLAN) not turning off immediately once + // Wi-Fi is disassociated or disabled + if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + || (mWifiManager.isWifiEnabled() + && mWifiManager.getConnectionInfo() != null + && mWifiManager.getConnectionInfo().getBSSID() != null)) { + if (DEBUG) { + Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss); + } + anySimReadyAndInService = true; + } } - }; + } + } + // Only create "No SIM card" if no cards with CarrierName && no wifi when some sim is READY + // This condition will also be true always when numSubs == 0 + if (allSimsMissing && !anySimReadyAndInService) { + if (numSubs != 0) { + // Shows "No SIM card | Emergency calls only" on devices that are voice-capable. + // This depends on mPlmn containing the text "Emergency calls only" when the radio + // has some connectivity. Otherwise, it should be null or empty and just show + // "No SIM card" + // Grab the first subscripton, because they all should contain the emergency text, + // described above. + displayText = makeCarrierStringOnEmergencyCapable( + getMissingSimMessage(), subs.get(0).getCarrierName()); + } else { + // We don't have a SubscriptionInfo to get the emergency calls only from. + // Grab it from the old sticky broadcast if possible instead. We can use it + // here because no subscriptions are active, so we don't have + // to worry about MSIM clashing. + CharSequence text = + getContext().getText(com.android.internal.R.string.emergency_calls_only); + Intent i = getContext().registerReceiver(null, + new IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)); + if (i != null) { + String spn = ""; + String plmn = ""; + if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)) { + spn = i.getStringExtra(TelephonyManager.EXTRA_SPN); + } + if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)) { + plmn = i.getStringExtra(TelephonyManager.EXTRA_PLMN); + } + if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn); + if (Objects.equals(plmn, spn)) { + text = plmn; + } else { + text = concatenate(plmn, spn, mSeparator); + } + } + displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text); + } + } + + if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames); + + displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, + allSimsMissing); + + boolean airplaneMode = false; + // APM (airplane mode) != no carrier state. There are carrier services + // (e.g. WFC = Wi-Fi calling) which may operate in APM. + if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { + displayText = getAirplaneModeMessage(); + airplaneMode = true; + } + + final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( + displayText, + carrierNames, + !allSimsMissing, + subsIds, + airplaneMode); + postToCallback(info); + } - @Inject - public CarrierTextController(CarrierText view, - CarrierTextManager.Builder carrierTextManagerBuilder, - KeyguardUpdateMonitor keyguardUpdateMonitor) { - super(view); + @VisibleForTesting + protected void postToCallback(CarrierTextCallbackInfo info) { + final CarrierTextCallback callback = mCarrierTextCallback; + if (callback != null) { + mMainHandler.post(() -> callback.updateCarrierInfo(info)); + } + } - mCarrierTextManager = carrierTextManagerBuilder - .setShowAirplaneMode(mView.getShowAirplaneMode()) - .setShowMissingSim(mView.getShowMissingSim()) - .build(); - mKeyguardUpdateMonitor = keyguardUpdateMonitor; + private Context getContext() { + return mContext; } - @Override - protected void onInit() { - super.onInit(); - mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive()); + private String getMissingSimMessage() { + return mShowMissingSim && mTelephonyCapable + ? getContext().getString(R.string.keyguard_missing_sim_message_short) : ""; } - @Override - protected void onViewAttached() { - mCarrierTextManager.setListening(mCarrierTextCallback); + private String getAirplaneModeMessage() { + return mShowAirplaneMode + ? getContext().getString(R.string.airplane_mode) : ""; } - @Override - protected void onViewDetached() { - mCarrierTextManager.setListening(null); + /** + * Top-level function for creating carrier text. Makes text based on simState, PLMN + * and SPN as well as device capabilities, such as being emergency call capable. + * + * @return Carrier text if not in missing state, null otherwise. + */ + private CharSequence getCarrierTextForSimState(int simState, CharSequence text) { + CharSequence carrierText = null; + CarrierTextController.StatusMode status = getStatusForIccState(simState); + switch (status) { + case Normal: + carrierText = text; + break; + + case SimNotReady: + // Null is reserved for denoting missing, in this case we have nothing to display. + carrierText = ""; // nothing to display yet. + break; + + case NetworkLocked: + carrierText = makeCarrierStringOnEmergencyCapable( + mContext.getText(R.string.keyguard_network_locked_message), text); + break; + + case SimMissing: + carrierText = null; + break; + + case SimPermDisabled: + carrierText = makeCarrierStringOnEmergencyCapable( + getContext().getText( + R.string.keyguard_permanent_disabled_sim_message_short), + text); + break; + + case SimMissingLocked: + carrierText = null; + break; + + case SimLocked: + carrierText = makeCarrierStringOnLocked( + getContext().getText(R.string.keyguard_sim_locked_message), + text); + break; + + case SimPukLocked: + carrierText = makeCarrierStringOnLocked( + getContext().getText(R.string.keyguard_sim_puk_locked_message), + text); + break; + case SimIoError: + carrierText = makeCarrierStringOnEmergencyCapable( + getContext().getText(R.string.keyguard_sim_error_message_short), + text); + break; + case SimUnknown: + carrierText = null; + break; + } + + return carrierText; + } + + /* + * Add emergencyCallMessage to carrier string only if phone supports emergency calls. + */ + private CharSequence makeCarrierStringOnEmergencyCapable( + CharSequence simMessage, CharSequence emergencyCallMessage) { + if (mIsEmergencyCallCapable) { + return concatenate(simMessage, emergencyCallMessage, mSeparator); + } + return simMessage; + } + + /* + * Add "SIM card is locked" in parenthesis after carrier name, so it is easily associated in + * DSDS + */ + private CharSequence makeCarrierStringOnLocked(CharSequence simMessage, + CharSequence carrierName) { + final boolean simMessageValid = !TextUtils.isEmpty(simMessage); + final boolean carrierNameValid = !TextUtils.isEmpty(carrierName); + if (simMessageValid && carrierNameValid) { + return mContext.getString(R.string.keyguard_carrier_name_with_sim_locked_template, + carrierName, simMessage); + } else if (simMessageValid) { + return simMessage; + } else if (carrierNameValid) { + return carrierName; + } else { + return ""; + } + } + + /** + * Determine the current status of the lock screen given the SIM state and other stuff. + */ + private CarrierTextController.StatusMode getStatusForIccState(int simState) { + final boolean missingAndNotProvisioned = + !mKeyguardUpdateMonitor.isDeviceProvisioned() + && (simState == TelephonyManager.SIM_STATE_ABSENT + || simState == TelephonyManager.SIM_STATE_PERM_DISABLED); + + // Assume we're NETWORK_LOCKED if not provisioned + simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState; + switch (simState) { + case TelephonyManager.SIM_STATE_ABSENT: + return CarrierTextController.StatusMode.SimMissing; + case TelephonyManager.SIM_STATE_NETWORK_LOCKED: + return CarrierTextController.StatusMode.SimMissingLocked; + case TelephonyManager.SIM_STATE_NOT_READY: + return CarrierTextController.StatusMode.SimNotReady; + case TelephonyManager.SIM_STATE_PIN_REQUIRED: + return CarrierTextController.StatusMode.SimLocked; + case TelephonyManager.SIM_STATE_PUK_REQUIRED: + return CarrierTextController.StatusMode.SimPukLocked; + case TelephonyManager.SIM_STATE_READY: + return CarrierTextController.StatusMode.Normal; + case TelephonyManager.SIM_STATE_PERM_DISABLED: + return CarrierTextController.StatusMode.SimPermDisabled; + case TelephonyManager.SIM_STATE_UNKNOWN: + return CarrierTextController.StatusMode.SimUnknown; + case TelephonyManager.SIM_STATE_CARD_IO_ERROR: + return CarrierTextController.StatusMode.SimIoError; + } + return CarrierTextController.StatusMode.SimUnknown; + } + + private static CharSequence concatenate(CharSequence plmn, CharSequence spn, + CharSequence separator) { + final boolean plmnValid = !TextUtils.isEmpty(plmn); + final boolean spnValid = !TextUtils.isEmpty(spn); + if (plmnValid && spnValid) { + return new StringBuilder().append(plmn).append(separator).append(spn).toString(); + } else if (plmnValid) { + return plmn; + } else if (spnValid) { + return spn; + } else { + return ""; + } + } + + /** + * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra + * separator added so there are no extra separators that are not needed. + */ + private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) { + int length = sequences.length; + if (length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (!TextUtils.isEmpty(sequences[i])) { + if (!TextUtils.isEmpty(sb)) { + sb.append(separator); + } + sb.append(sequences[i]); + } + } + return sb.toString(); + } + + private static List<CharSequence> append(List<CharSequence> list, CharSequence string) { + if (!TextUtils.isEmpty(string)) { + list.add(string); + } + return list; + } + + private CharSequence getCarrierHelpTextForSimState(int simState, + String plmn, String spn) { + int carrierHelpTextId = 0; + CarrierTextController.StatusMode status = getStatusForIccState(simState); + switch (status) { + case NetworkLocked: + carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled; + break; + + case SimMissing: + carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long; + break; + + case SimPermDisabled: + carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions; + break; + + case SimMissingLocked: + carrierHelpTextId = R.string.keyguard_missing_sim_instructions; + break; + + case Normal: + case SimLocked: + case SimPukLocked: + break; + } + + return mContext.getText(carrierHelpTextId); + } + + public static class Builder { + private final Context mContext; + private final String mSeparator; + private boolean mShowAirplaneMode; + private boolean mShowMissingSim; + + @Inject + public Builder(Context context, @Main Resources resources) { + mContext = context; + mSeparator = resources.getString( + com.android.internal.R.string.kg_text_message_separator); + } + + + public Builder setShowAirplaneMode(boolean showAirplaneMode) { + mShowAirplaneMode = showAirplaneMode; + return this; + } + + public Builder setShowMissingSim(boolean showMissingSim) { + mShowMissingSim = showMissingSim; + return this; + } + + public CarrierTextController build() { + return new CarrierTextController( + mContext, mSeparator, mShowAirplaneMode, mShowMissingSim); + } + } + /** + * Data structure for passing information to CarrierTextController subscribers + */ + public static final class CarrierTextCallbackInfo { + public final CharSequence carrierText; + public final CharSequence[] listOfCarriers; + public final boolean anySimReady; + public final int[] subscriptionIds; + public boolean airplaneMode; + + @VisibleForTesting + public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, + boolean anySimReady, int[] subscriptionIds) { + this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false); + } + + @VisibleForTesting + public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, + boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) { + this.carrierText = carrierText; + this.listOfCarriers = listOfCarriers; + this.anySimReady = anySimReady; + this.subscriptionIds = subscriptionIds; + this.airplaneMode = airplaneMode; + } + } + + /** + * Callback to communicate to Views + */ + public interface CarrierTextCallback { + /** + * Provides updated carrier information. + */ + default void updateCarrierInfo(CarrierTextCallbackInfo info) {}; + + /** + * Notifies the View that the device is going to sleep + */ + default void startedGoingToSleep() {}; + + /** + * Notifies the View that the device finished waking up + */ + default void finishedWakingUp() {}; } } diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java deleted file mode 100644 index 87b01e8671f0..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java +++ /dev/null @@ -1,720 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.keyguard; - -import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.net.ConnectivityManager; -import android.net.wifi.WifiManager; -import android.os.Handler; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; -import android.telephony.SubscriptionInfo; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import com.android.settingslib.WirelessUtils; -import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.Background; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.WakefulnessLifecycle; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.inject.Inject; - -/** - * Controller that generates text including the carrier names and/or the status of all the SIM - * interfaces in the device. Through a callback, the updates can be retrieved either as a list or - * separated by a given separator {@link CharSequence}. - */ -public class CarrierTextManager { - private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final String TAG = "CarrierTextController"; - - private final boolean mIsEmergencyCallCapable; - private final Handler mMainHandler; - private final Handler mBgHandler; - private boolean mTelephonyCapable; - private final boolean mShowMissingSim; - private final boolean mShowAirplaneMode; - private final AtomicBoolean mNetworkSupported = new AtomicBoolean(); - @VisibleForTesting - protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private final WifiManager mWifiManager; - private final boolean[] mSimErrorState; - private final int mSimSlotsNumber; - @Nullable // Check for nullability before dispatching - private CarrierTextCallback mCarrierTextCallback; - private final Context mContext; - private final TelephonyManager mTelephonyManager; - private final CharSequence mSeparator; - private final WakefulnessLifecycle mWakefulnessLifecycle; - private final WakefulnessLifecycle.Observer mWakefulnessObserver = - new WakefulnessLifecycle.Observer() { - @Override - public void onFinishedWakingUp() { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) callback.finishedWakingUp(); - } - - @Override - public void onStartedGoingToSleep() { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) callback.startedGoingToSleep(); - } - }; - - @VisibleForTesting - protected final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() { - @Override - public void onRefreshCarrierInfo() { - if (DEBUG) { - Log.d(TAG, "onRefreshCarrierInfo(), mTelephonyCapable: " - + Boolean.toString(mTelephonyCapable)); - } - updateCarrierText(); - } - - @Override - public void onTelephonyCapable(boolean capable) { - if (DEBUG) { - Log.d(TAG, "onTelephonyCapable() mTelephonyCapable: " - + Boolean.toString(capable)); - } - mTelephonyCapable = capable; - updateCarrierText(); - } - - public void onSimStateChanged(int subId, int slotId, int simState) { - if (slotId < 0 || slotId >= mSimSlotsNumber) { - Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId - + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable)); - return; - } - - if (DEBUG) Log.d(TAG, "onSimStateChanged: " + getStatusForIccState(simState)); - if (getStatusForIccState(simState) == CarrierTextManager.StatusMode.SimIoError) { - mSimErrorState[slotId] = true; - updateCarrierText(); - } else if (mSimErrorState[slotId]) { - mSimErrorState[slotId] = false; - updateCarrierText(); - } - } - }; - - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - if (mNetworkSupported.get() && mCarrierTextCallback != null) { - updateCarrierText(); - } - } - }; - - /** - * The status of this lock screen. Primarily used for widgets on LockScreen. - */ - private enum StatusMode { - Normal, // Normal case (sim card present, it's not locked) - NetworkLocked, // SIM card is 'network locked'. - SimMissing, // SIM card is missing. - SimMissingLocked, // SIM card is missing, and device isn't provisioned; don't allow access - SimPukLocked, // SIM card is PUK locked because SIM entered wrong too many times - SimLocked, // SIM card is currently locked - SimPermDisabled, // SIM card is permanently disabled due to PUK unlock failure - SimNotReady, // SIM is not ready yet. May never be on devices w/o a SIM. - SimIoError, // SIM card is faulty - SimUnknown // SIM card is unknown - } - - /** - * Controller that provides updates on text with carriers names or SIM status. - * Used by {@link CarrierText}. - * - * @param separator Separator between different parts of the text - */ - private CarrierTextManager(Context context, CharSequence separator, boolean showAirplaneMode, - boolean showMissingSim, @Nullable WifiManager wifiManager, - ConnectivityManager connectivityManager, TelephonyManager telephonyManager, - WakefulnessLifecycle wakefulnessLifecycle, @Main Handler mainHandler, - @Background Handler bgHandler, KeyguardUpdateMonitor keyguardUpdateMonitor) { - mContext = context; - mIsEmergencyCallCapable = telephonyManager.isVoiceCapable(); - - mShowAirplaneMode = showAirplaneMode; - mShowMissingSim = showMissingSim; - - mWifiManager = wifiManager; - mTelephonyManager = telephonyManager; - mSeparator = separator; - mWakefulnessLifecycle = wakefulnessLifecycle; - mSimSlotsNumber = getTelephonyManager().getSupportedModemCount(); - mSimErrorState = new boolean[mSimSlotsNumber]; - mMainHandler = mainHandler; - mBgHandler = bgHandler; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mBgHandler.post(() -> { - boolean supported = connectivityManager.isNetworkSupported( - ConnectivityManager.TYPE_MOBILE); - if (supported && mNetworkSupported.compareAndSet(false, supported)) { - // This will set/remove the listeners appropriately. Note that it will never double - // add the listeners. - handleSetListening(mCarrierTextCallback); - } - }); - } - - private TelephonyManager getTelephonyManager() { - return mTelephonyManager; - } - - /** - * Checks if there are faulty cards. Adds the text depending on the slot of the card - * - * @param text: current carrier text based on the sim state - * @param carrierNames names order by subscription order - * @param subOrderBySlot array containing the sub index for each slot ID - * @param noSims: whether a valid sim card is inserted - * @return text - */ - private CharSequence updateCarrierTextWithSimIoError(CharSequence text, - CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) { - final CharSequence carrier = ""; - CharSequence carrierTextForSimIOError = getCarrierTextForSimState( - TelephonyManager.SIM_STATE_CARD_IO_ERROR, carrier); - // mSimErrorState has the state of each sim indexed by slotID. - for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) { - if (!mSimErrorState[index]) { - continue; - } - // In the case when no sim cards are detected but a faulty card is inserted - // overwrite the text and only show "Invalid card" - if (noSims) { - return concatenate(carrierTextForSimIOError, - getContext().getText( - com.android.internal.R.string.emergency_calls_only), - mSeparator); - } else if (subOrderBySlot[index] != -1) { - int subIndex = subOrderBySlot[index]; - // prepend "Invalid card" when faulty card is inserted in slot 0 or 1 - carrierNames[subIndex] = concatenate(carrierTextForSimIOError, - carrierNames[subIndex], - mSeparator); - } else { - // concatenate "Invalid card" when faulty card is inserted in other slot - text = concatenate(text, carrierTextForSimIOError, mSeparator); - } - - } - return text; - } - - /** - * This may be called internally after retrieving the correct value of {@code mNetworkSupported} - * (assumed false to start). In that case, the following happens: - * <ul> - * <li> If there was a registered callback, and the network is supported, it will register - * listeners. - * <li> If there was not a registered callback, it will try to remove unregistered listeners - * which is a no-op - * </ul> - * - * This call will always be processed in a background thread. - */ - private void handleSetListening(CarrierTextCallback callback) { - TelephonyManager telephonyManager = getTelephonyManager(); - if (callback != null) { - mCarrierTextCallback = callback; - if (mNetworkSupported.get()) { - // Keyguard update monitor expects callbacks from main thread - mMainHandler.post(() -> mKeyguardUpdateMonitor.registerCallback(mCallback)); - mWakefulnessLifecycle.addObserver(mWakefulnessObserver); - telephonyManager.listen(mPhoneStateListener, - LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); - } else { - // Don't listen and clear out the text when the device isn't a phone. - mMainHandler.post(() -> callback.updateCarrierInfo( - new CarrierTextCallbackInfo("", null, false, null) - )); - } - } else { - mCarrierTextCallback = null; - mMainHandler.post(() -> mKeyguardUpdateMonitor.removeCallback(mCallback)); - mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); - telephonyManager.listen(mPhoneStateListener, LISTEN_NONE); - } - } - - /** - * Sets the listening status of this controller. If the callback is null, it is set to - * not listening. - * - * @param callback Callback to provide text updates - */ - public void setListening(CarrierTextCallback callback) { - mBgHandler.post(() -> handleSetListening(callback)); - } - - protected List<SubscriptionInfo> getSubscriptionInfo() { - return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); - } - - protected void updateCarrierText() { - boolean allSimsMissing = true; - boolean anySimReadyAndInService = false; - CharSequence displayText = null; - List<SubscriptionInfo> subs = getSubscriptionInfo(); - - final int numSubs = subs.size(); - final int[] subsIds = new int[numSubs]; - // This array will contain in position i, the index of subscription in slot ID i. - // -1 if no subscription in that slot - final int[] subOrderBySlot = new int[mSimSlotsNumber]; - for (int i = 0; i < mSimSlotsNumber; i++) { - subOrderBySlot[i] = -1; - } - final CharSequence[] carrierNames = new CharSequence[numSubs]; - if (DEBUG) Log.d(TAG, "updateCarrierText(): " + numSubs); - - for (int i = 0; i < numSubs; i++) { - int subId = subs.get(i).getSubscriptionId(); - carrierNames[i] = ""; - subsIds[i] = subId; - subOrderBySlot[subs.get(i).getSimSlotIndex()] = i; - int simState = mKeyguardUpdateMonitor.getSimState(subId); - CharSequence carrierName = subs.get(i).getCarrierName(); - CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName); - if (DEBUG) { - Log.d(TAG, "Handling (subId=" + subId + "): " + simState + " " + carrierName); - } - if (carrierTextForSimState != null) { - allSimsMissing = false; - carrierNames[i] = carrierTextForSimState; - } - if (simState == TelephonyManager.SIM_STATE_READY) { - ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId); - if (ss != null && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) { - // hack for WFC (IWLAN) not turning off immediately once - // Wi-Fi is disassociated or disabled - if (ss.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN - || (mWifiManager != null && mWifiManager.isWifiEnabled() - && mWifiManager.getConnectionInfo() != null - && mWifiManager.getConnectionInfo().getBSSID() != null)) { - if (DEBUG) { - Log.d(TAG, "SIM ready and in service: subId=" + subId + ", ss=" + ss); - } - anySimReadyAndInService = true; - } - } - } - } - // Only create "No SIM card" if no cards with CarrierName && no wifi when some sim is READY - // This condition will also be true always when numSubs == 0 - if (allSimsMissing && !anySimReadyAndInService) { - if (numSubs != 0) { - // Shows "No SIM card | Emergency calls only" on devices that are voice-capable. - // This depends on mPlmn containing the text "Emergency calls only" when the radio - // has some connectivity. Otherwise, it should be null or empty and just show - // "No SIM card" - // Grab the first subscripton, because they all should contain the emergency text, - // described above. - displayText = makeCarrierStringOnEmergencyCapable( - getMissingSimMessage(), subs.get(0).getCarrierName()); - } else { - // We don't have a SubscriptionInfo to get the emergency calls only from. - // Grab it from the old sticky broadcast if possible instead. We can use it - // here because no subscriptions are active, so we don't have - // to worry about MSIM clashing. - CharSequence text = - getContext().getText(com.android.internal.R.string.emergency_calls_only); - Intent i = getContext().registerReceiver(null, - new IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)); - if (i != null) { - String spn = ""; - String plmn = ""; - if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)) { - spn = i.getStringExtra(TelephonyManager.EXTRA_SPN); - } - if (i.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)) { - plmn = i.getStringExtra(TelephonyManager.EXTRA_PLMN); - } - if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn); - if (Objects.equals(plmn, spn)) { - text = plmn; - } else { - text = concatenate(plmn, spn, mSeparator); - } - } - displayText = makeCarrierStringOnEmergencyCapable(getMissingSimMessage(), text); - } - } - - if (TextUtils.isEmpty(displayText)) displayText = joinNotEmpty(mSeparator, carrierNames); - - displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot, - allSimsMissing); - - boolean airplaneMode = false; - // APM (airplane mode) != no carrier state. There are carrier services - // (e.g. WFC = Wi-Fi calling) which may operate in APM. - if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) { - displayText = getAirplaneModeMessage(); - airplaneMode = true; - } - - final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo( - displayText, - carrierNames, - !allSimsMissing, - subsIds, - airplaneMode); - postToCallback(info); - } - - @VisibleForTesting - protected void postToCallback(CarrierTextCallbackInfo info) { - final CarrierTextCallback callback = mCarrierTextCallback; - if (callback != null) { - mMainHandler.post(() -> callback.updateCarrierInfo(info)); - } - } - - private Context getContext() { - return mContext; - } - - private String getMissingSimMessage() { - return mShowMissingSim && mTelephonyCapable - ? getContext().getString(R.string.keyguard_missing_sim_message_short) : ""; - } - - private String getAirplaneModeMessage() { - return mShowAirplaneMode - ? getContext().getString(R.string.airplane_mode) : ""; - } - - /** - * Top-level function for creating carrier text. Makes text based on simState, PLMN - * and SPN as well as device capabilities, such as being emergency call capable. - * - * @return Carrier text if not in missing state, null otherwise. - */ - private CharSequence getCarrierTextForSimState(int simState, CharSequence text) { - CharSequence carrierText = null; - CarrierTextManager.StatusMode status = getStatusForIccState(simState); - switch (status) { - case Normal: - carrierText = text; - break; - - case SimNotReady: - // Null is reserved for denoting missing, in this case we have nothing to display. - carrierText = ""; // nothing to display yet. - break; - - case NetworkLocked: - carrierText = makeCarrierStringOnEmergencyCapable( - mContext.getText(R.string.keyguard_network_locked_message), text); - break; - - case SimMissing: - carrierText = null; - break; - - case SimPermDisabled: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText( - R.string.keyguard_permanent_disabled_sim_message_short), - text); - break; - - case SimMissingLocked: - carrierText = null; - break; - - case SimLocked: - carrierText = makeCarrierStringOnLocked( - getContext().getText(R.string.keyguard_sim_locked_message), - text); - break; - - case SimPukLocked: - carrierText = makeCarrierStringOnLocked( - getContext().getText(R.string.keyguard_sim_puk_locked_message), - text); - break; - case SimIoError: - carrierText = makeCarrierStringOnEmergencyCapable( - getContext().getText(R.string.keyguard_sim_error_message_short), - text); - break; - case SimUnknown: - carrierText = null; - break; - } - - return carrierText; - } - - /* - * Add emergencyCallMessage to carrier string only if phone supports emergency calls. - */ - private CharSequence makeCarrierStringOnEmergencyCapable( - CharSequence simMessage, CharSequence emergencyCallMessage) { - if (mIsEmergencyCallCapable) { - return concatenate(simMessage, emergencyCallMessage, mSeparator); - } - return simMessage; - } - - /* - * Add "SIM card is locked" in parenthesis after carrier name, so it is easily associated in - * DSDS - */ - private CharSequence makeCarrierStringOnLocked(CharSequence simMessage, - CharSequence carrierName) { - final boolean simMessageValid = !TextUtils.isEmpty(simMessage); - final boolean carrierNameValid = !TextUtils.isEmpty(carrierName); - if (simMessageValid && carrierNameValid) { - return mContext.getString(R.string.keyguard_carrier_name_with_sim_locked_template, - carrierName, simMessage); - } else if (simMessageValid) { - return simMessage; - } else if (carrierNameValid) { - return carrierName; - } else { - return ""; - } - } - - /** - * Determine the current status of the lock screen given the SIM state and other stuff. - */ - private CarrierTextManager.StatusMode getStatusForIccState(int simState) { - final boolean missingAndNotProvisioned = - !mKeyguardUpdateMonitor.isDeviceProvisioned() - && (simState == TelephonyManager.SIM_STATE_ABSENT - || simState == TelephonyManager.SIM_STATE_PERM_DISABLED); - - // Assume we're NETWORK_LOCKED if not provisioned - simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState; - switch (simState) { - case TelephonyManager.SIM_STATE_ABSENT: - return CarrierTextManager.StatusMode.SimMissing; - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - return CarrierTextManager.StatusMode.SimMissingLocked; - case TelephonyManager.SIM_STATE_NOT_READY: - return CarrierTextManager.StatusMode.SimNotReady; - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - return CarrierTextManager.StatusMode.SimLocked; - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - return CarrierTextManager.StatusMode.SimPukLocked; - case TelephonyManager.SIM_STATE_READY: - return CarrierTextManager.StatusMode.Normal; - case TelephonyManager.SIM_STATE_PERM_DISABLED: - return CarrierTextManager.StatusMode.SimPermDisabled; - case TelephonyManager.SIM_STATE_UNKNOWN: - return CarrierTextManager.StatusMode.SimUnknown; - case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - return CarrierTextManager.StatusMode.SimIoError; - } - return CarrierTextManager.StatusMode.SimUnknown; - } - - private static CharSequence concatenate(CharSequence plmn, CharSequence spn, - CharSequence separator) { - final boolean plmnValid = !TextUtils.isEmpty(plmn); - final boolean spnValid = !TextUtils.isEmpty(spn); - if (plmnValid && spnValid) { - return new StringBuilder().append(plmn).append(separator).append(spn).toString(); - } else if (plmnValid) { - return plmn; - } else if (spnValid) { - return spn; - } else { - return ""; - } - } - - /** - * Joins the strings in a sequence using a separator. Empty strings are discarded with no extra - * separator added so there are no extra separators that are not needed. - */ - private static CharSequence joinNotEmpty(CharSequence separator, CharSequence[] sequences) { - int length = sequences.length; - if (length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (!TextUtils.isEmpty(sequences[i])) { - if (!TextUtils.isEmpty(sb)) { - sb.append(separator); - } - sb.append(sequences[i]); - } - } - return sb.toString(); - } - - private static List<CharSequence> append(List<CharSequence> list, CharSequence string) { - if (!TextUtils.isEmpty(string)) { - list.add(string); - } - return list; - } - - private CharSequence getCarrierHelpTextForSimState(int simState, - String plmn, String spn) { - int carrierHelpTextId = 0; - CarrierTextManager.StatusMode status = getStatusForIccState(simState); - switch (status) { - case NetworkLocked: - carrierHelpTextId = R.string.keyguard_instructions_when_pattern_disabled; - break; - - case SimMissing: - carrierHelpTextId = R.string.keyguard_missing_sim_instructions_long; - break; - - case SimPermDisabled: - carrierHelpTextId = R.string.keyguard_permanent_disabled_sim_instructions; - break; - - case SimMissingLocked: - carrierHelpTextId = R.string.keyguard_missing_sim_instructions; - break; - - case Normal: - case SimLocked: - case SimPukLocked: - break; - } - - return mContext.getText(carrierHelpTextId); - } - - /** Injectable Buildeer for {@#link CarrierTextManager}. */ - public static class Builder { - private final Context mContext; - private final String mSeparator; - private final WifiManager mWifiManager; - private final ConnectivityManager mConnectivityManager; - private final TelephonyManager mTelephonyManager; - private final WakefulnessLifecycle mWakefulnessLifecycle; - private final Handler mMainHandler; - private final Handler mBgHandler; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private boolean mShowAirplaneMode; - private boolean mShowMissingSim; - - @Inject - public Builder(Context context, @Main Resources resources, - @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager, - TelephonyManager telephonyManager, WakefulnessLifecycle wakefulnessLifecycle, - @Main Handler mainHandler, @Background Handler bgHandler, - KeyguardUpdateMonitor keyguardUpdateMonitor) { - mContext = context; - mSeparator = resources.getString( - com.android.internal.R.string.kg_text_message_separator); - mWifiManager = wifiManager; - mConnectivityManager = connectivityManager; - mTelephonyManager = telephonyManager; - mWakefulnessLifecycle = wakefulnessLifecycle; - mMainHandler = mainHandler; - mBgHandler = bgHandler; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; - } - - /** */ - public Builder setShowAirplaneMode(boolean showAirplaneMode) { - mShowAirplaneMode = showAirplaneMode; - return this; - } - - /** */ - public Builder setShowMissingSim(boolean showMissingSim) { - mShowMissingSim = showMissingSim; - return this; - } - - /** Create a CarrierTextManager. */ - public CarrierTextManager build() { - return new CarrierTextManager( - mContext, mSeparator, mShowAirplaneMode, mShowMissingSim, mWifiManager, - mConnectivityManager, mTelephonyManager, mWakefulnessLifecycle, mMainHandler, - mBgHandler, mKeyguardUpdateMonitor); - } - } - /** - * Data structure for passing information to CarrierTextController subscribers - */ - public static final class CarrierTextCallbackInfo { - public final CharSequence carrierText; - public final CharSequence[] listOfCarriers; - public final boolean anySimReady; - public final int[] subscriptionIds; - public boolean airplaneMode; - - @VisibleForTesting - public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, - boolean anySimReady, int[] subscriptionIds) { - this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false); - } - - @VisibleForTesting - public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers, - boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) { - this.carrierText = carrierText; - this.listOfCarriers = listOfCarriers; - this.anySimReady = anySimReady; - this.subscriptionIds = subscriptionIds; - this.airplaneMode = airplaneMode; - } - } - - /** - * Callback to communicate to Views - */ - public interface CarrierTextCallback { - /** - * Provides updated carrier information. - */ - default void updateCarrierInfo(CarrierTextCallbackInfo info) {}; - - /** - * Notifies the View that the device is going to sleep - */ - default void startedGoingToSleep() {}; - - /** - * Notifies the View that the device finished waking up - */ - default void finishedWakingUp() {}; - } -} diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java index c4b02f62f291..707ee298a55a 100644 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java +++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java @@ -16,16 +16,34 @@ package com.android.keyguard; +import static com.android.systemui.DejankUtils.whitelistIpcs; + +import android.app.ActivityOptions; +import android.app.ActivityTaskManager; import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.Button; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.EmergencyAffordanceManager; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.Utils; +import com.android.systemui.Dependency; +import com.android.systemui.util.EmergencyDialerConstants; /** * This class implements a smart emergency button that updates itself based @@ -35,14 +53,34 @@ import com.android.settingslib.Utils; */ public class EmergencyButton extends Button { + private static final String LOG_TAG = "EmergencyButton"; private final EmergencyAffordanceManager mEmergencyAffordanceManager; private int mDownX; private int mDownY; + KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { + + @Override + public void onSimStateChanged(int subId, int slotId, int simState) { + updateEmergencyCallButton(); + } + + @Override + public void onPhoneStateChanged(int phoneState) { + updateEmergencyCallButton(); + } + }; private boolean mLongPressWasDragged; + public interface EmergencyButtonCallback { + public void onEmergencyButtonClickedWhenInCall(); + } + private LockPatternUtils mLockPatternUtils; + private PowerManager mPowerManager; + private EmergencyButtonCallback mEmergencyButtonCallback; + private final boolean mIsVoiceCapable; private final boolean mEnableEmergencyCallWhileSimLocked; public EmergencyButton(Context context) { @@ -51,15 +89,34 @@ public class EmergencyButton extends Button { public EmergencyButton(Context context, AttributeSet attrs) { super(context, attrs); + mIsVoiceCapable = getTelephonyManager().isVoiceCapable(); mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked); mEmergencyAffordanceManager = new EmergencyAffordanceManager(context); } + private TelephonyManager getTelephonyManager() { + return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); mLockPatternUtils = new LockPatternUtils(mContext); + mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + setOnClickListener(v -> takeEmergencyCallAction()); if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { setOnLongClickListener(v -> { if (!mLongPressWasDragged @@ -70,6 +127,7 @@ public class EmergencyButton extends Button { return false; }); } + whitelistIpcs(this::updateEmergencyCallButton); } @Override @@ -107,13 +165,65 @@ public class EmergencyButton extends Button { return super.performLongClick(); } - void updateEmergencyCallButton(boolean isInCall, boolean isVoiceCapable, boolean simLocked) { + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + updateEmergencyCallButton(); + } + + /** + * Shows the emergency dialer or returns the user to the existing call. + */ + public void takeEmergencyCallAction() { + MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_CALL); + if (mPowerManager != null) { + mPowerManager.userActivity(SystemClock.uptimeMillis(), true); + } + try { + ActivityTaskManager.getService().stopSystemLockTaskMode(); + } catch (RemoteException e) { + Slog.w(LOG_TAG, "Failed to stop app pinning"); + } + if (isInCall()) { + resumeCall(); + if (mEmergencyButtonCallback != null) { + mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall(); + } + } else { + KeyguardUpdateMonitor updateMonitor = Dependency.get(KeyguardUpdateMonitor.class); + if (updateMonitor != null) { + updateMonitor.reportEmergencyCallAction(true /* bypassHandler */); + } else { + Log.w(LOG_TAG, "KeyguardUpdateMonitor was null, launching intent anyway."); + } + TelecomManager telecomManager = getTelecommManager(); + if (telecomManager == null) { + Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer"); + return; + } + Intent emergencyDialIntent = + telecomManager.createLaunchEmergencyDialerIntent(null /* number*/) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, + EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON); + + getContext().startActivityAsUser(emergencyDialIntent, + ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), + new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); + } + } + + private void updateEmergencyCallButton() { boolean visible = false; - if (isVoiceCapable) { + if (mIsVoiceCapable) { // Emergency calling requires voice capability. - if (isInCall) { + if (isInCall()) { visible = true; // always show "return to call" if phone is off-hook } else { + final boolean simLocked = Dependency.get(KeyguardUpdateMonitor.class) + .isSimPinVoiceSecure(); if (simLocked) { // Some countries can't handle emergency calls while SIM is locked. visible = mEnableEmergencyCallWhileSimLocked; @@ -127,7 +237,7 @@ public class EmergencyButton extends Button { setVisibility(View.VISIBLE); int textId; - if (isInCall) { + if (isInCall()) { textId = com.android.internal.R.string.lockscreen_return_to_call; } else { textId = com.android.internal.R.string.lockscreen_emergency_call; @@ -137,4 +247,26 @@ public class EmergencyButton extends Button { setVisibility(View.GONE); } } + + public void setCallback(EmergencyButtonCallback callback) { + mEmergencyButtonCallback = callback; + } + + /** + * Resumes a call in progress. + */ + private void resumeCall() { + getTelecommManager().showInCallScreen(false); + } + + /** + * @return {@code true} if there is a call currently in progress. + */ + private boolean isInCall() { + return getTelecommManager().isInCall(); + } + + private TelecomManager getTelecommManager() { + return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); + } } diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java deleted file mode 100644 index 4275189cfe26..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.keyguard; - -import static com.android.systemui.DejankUtils.whitelistIpcs; - -import android.app.ActivityOptions; -import android.app.ActivityTaskManager; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.PowerManager; -import android.os.SystemClock; -import android.os.UserHandle; -import android.telecom.TelecomManager; -import android.telephony.TelephonyManager; -import android.util.Log; - -import androidx.annotation.Nullable; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.keyguard.dagger.KeyguardBouncerScope; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; -import com.android.systemui.util.EmergencyDialerConstants; -import com.android.systemui.util.ViewController; - -import javax.inject.Inject; - -/** View Controller for {@link com.android.keyguard.EmergencyButton}. */ -@KeyguardBouncerScope -public class EmergencyButtonController extends ViewController<EmergencyButton> { - static final String LOG_TAG = "EmergencyButton"; - private final ConfigurationController mConfigurationController; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private final TelephonyManager mTelephonyManager; - private final PowerManager mPowerManager; - private final ActivityTaskManager mActivityTaskManager; - private final TelecomManager mTelecomManager; - private final MetricsLogger mMetricsLogger; - - private EmergencyButtonCallback mEmergencyButtonCallback; - - private final KeyguardUpdateMonitorCallback mInfoCallback = - new KeyguardUpdateMonitorCallback() { - @Override - public void onSimStateChanged(int subId, int slotId, int simState) { - updateEmergencyCallButton(); - } - - @Override - public void onPhoneStateChanged(int phoneState) { - updateEmergencyCallButton(); - } - }; - - private final ConfigurationListener mConfigurationListener = new ConfigurationListener() { - @Override - public void onConfigChanged(Configuration newConfig) { - updateEmergencyCallButton(); - } - }; - - private EmergencyButtonController(@Nullable EmergencyButton view, - ConfigurationController configurationController, - KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, - PowerManager powerManager, ActivityTaskManager activityTaskManager, - @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { - super(view); - mConfigurationController = configurationController; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mTelephonyManager = telephonyManager; - mPowerManager = powerManager; - mActivityTaskManager = activityTaskManager; - mTelecomManager = telecomManager; - mMetricsLogger = metricsLogger; - } - - @Override - protected void onInit() { - whitelistIpcs(this::updateEmergencyCallButton); - } - - @Override - protected void onViewAttached() { - mKeyguardUpdateMonitor.registerCallback(mInfoCallback); - mConfigurationController.addCallback(mConfigurationListener); - mView.setOnClickListener(v -> takeEmergencyCallAction()); - } - - @Override - protected void onViewDetached() { - mKeyguardUpdateMonitor.removeCallback(mInfoCallback); - mConfigurationController.removeCallback(mConfigurationListener); - } - - private void updateEmergencyCallButton() { - if (mView != null) { - mView.updateEmergencyCallButton( - mTelecomManager != null && mTelecomManager.isInCall(), - mTelephonyManager.isVoiceCapable(), - mKeyguardUpdateMonitor.isSimPinVoiceSecure()); - } - } - - public void setEmergencyButtonCallback(EmergencyButtonCallback callback) { - mEmergencyButtonCallback = callback; - } - /** - * Shows the emergency dialer or returns the user to the existing call. - */ - public void takeEmergencyCallAction() { - mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL); - if (mPowerManager != null) { - mPowerManager.userActivity(SystemClock.uptimeMillis(), true); - } - mActivityTaskManager.stopSystemLockTaskMode(); - if (mTelecomManager != null && mTelecomManager.isInCall()) { - mTelecomManager.showInCallScreen(false); - if (mEmergencyButtonCallback != null) { - mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall(); - } - } else { - mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */); - if (mTelecomManager == null) { - Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer"); - return; - } - Intent emergencyDialIntent = - mTelecomManager.createLaunchEmergencyDialerIntent(null /* number*/) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_CLEAR_TOP) - .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, - EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON); - - getContext().startActivityAsUser(emergencyDialIntent, - ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), - new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); - } - } - - /** */ - public interface EmergencyButtonCallback { - /** */ - void onEmergencyButtonClickedWhenInCall(); - } - - /** Injectable Factory for creating {@link EmergencyButtonController}. */ - public static class Factory { - private final ConfigurationController mConfigurationController; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; - private final TelephonyManager mTelephonyManager; - private final PowerManager mPowerManager; - private final ActivityTaskManager mActivityTaskManager; - @Nullable - private final TelecomManager mTelecomManager; - private final MetricsLogger mMetricsLogger; - - @Inject - public Factory(ConfigurationController configurationController, - KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, - PowerManager powerManager, ActivityTaskManager activityTaskManager, - @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger) { - - mConfigurationController = configurationController; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mTelephonyManager = telephonyManager; - mPowerManager = powerManager; - mActivityTaskManager = activityTaskManager; - mTelecomManager = telecomManager; - mMetricsLogger = metricsLogger; - } - - /** Construct an {@link com.android.keyguard.EmergencyButtonController}. */ - public EmergencyButtonController create(EmergencyButton view) { - return new EmergencyButtonController(view, mConfigurationController, - mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager, - mTelecomManager, mMetricsLogger); - } - } -} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java index 7a05a17c8010..5760565aaab1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java @@ -31,7 +31,7 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; -import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; +import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; @@ -41,7 +41,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final LockPatternUtils mLockPatternUtils; private final LatencyTracker mLatencyTracker; - private final EmergencyButtonController mEmergencyButtonController; private CountDownTimer mCountdownTimer; protected KeyguardMessageAreaController mMessageAreaController; private boolean mDismissing; @@ -71,12 +70,11 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, - LatencyTracker latencyTracker, EmergencyButtonController emergencyButtonController) { - super(view, securityMode, keyguardSecurityCallback, emergencyButtonController); + LatencyTracker latencyTracker) { + super(view, securityMode, keyguardSecurityCallback); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; - mEmergencyButtonController = emergencyButtonController; KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); mMessageAreaController = messageAreaControllerFactory.create(kma); } @@ -85,7 +83,6 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey @Override public void onInit() { - super.onInit(); mMessageAreaController.init(); } @@ -94,7 +91,10 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey super.onViewAttached(); mView.setKeyDownListener(mKeyDownListener); mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled()); - mEmergencyButtonController.setEmergencyButtonCallback(mEmergencyButtonCallback); + EmergencyButton button = mView.findViewById(R.id.emergency_call_button); + if (button != null) { + button.setCallback(mEmergencyButtonCallback); + } } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 76a7473e25e8..276036c400e1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -36,6 +36,7 @@ import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.dagger.KeyguardStatusViewComponent; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.navigationbar.NavigationBarController; @@ -45,15 +46,12 @@ import java.util.concurrent.Executor; import javax.inject.Inject; -import dagger.Lazy; - public class KeyguardDisplayManager { protected static final String TAG = "KeyguardDisplayManager"; private static boolean DEBUG = KeyguardConstants.DEBUG; private MediaRouter mMediaRouter = null; private final DisplayManager mDisplayService; - private final Lazy<NavigationBarController> mNavigationBarControllerLazy; private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final Context mContext; @@ -87,11 +85,9 @@ public class KeyguardDisplayManager { @Inject public KeyguardDisplayManager(Context context, - Lazy<NavigationBarController> navigationBarControllerLazy, KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, @UiBackground Executor uiBgExecutor) { mContext = context; - mNavigationBarControllerLazy = navigationBarControllerLazy; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; uiBgExecutor.execute(() -> mMediaRouter = mContext.getSystemService(MediaRouter.class)); mDisplayService = mContext.getSystemService(DisplayManager.class); @@ -244,7 +240,7 @@ public class KeyguardDisplayManager { // Leave this task to {@link StatusBarKeyguardViewManager} if (displayId == DEFAULT_DISPLAY) return; - NavigationBarView navBarView = mNavigationBarControllerLazy.get() + NavigationBarView navBarView = Dependency.get(NavigationBarController.class) .getNavigationBarView(displayId); // We may not have nav bar on a display. if (navBarView == null) return; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java index a0c5958284ec..957882dc9c6b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java @@ -42,7 +42,6 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> private final SecurityMode mSecurityMode; private final KeyguardSecurityCallback mKeyguardSecurityCallback; private final EmergencyButton mEmergencyButton; - private final EmergencyButtonController mEmergencyButtonController; private boolean mPaused; @@ -70,18 +69,11 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> }; protected KeyguardInputViewController(T view, SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback, - EmergencyButtonController emergencyButtonController) { + KeyguardSecurityCallback keyguardSecurityCallback) { super(view); mSecurityMode = securityMode; mKeyguardSecurityCallback = keyguardSecurityCallback; mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button); - mEmergencyButtonController = emergencyButtonController; - } - - @Override - protected void onInit() { - mEmergencyButtonController.init(); } @Override @@ -163,9 +155,8 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> private final InputMethodManager mInputMethodManager; private final DelayableExecutor mMainExecutor; private final Resources mResources; - private final LiftToActivateListener mLiftToActivateListener; - private final TelephonyManager mTelephonyManager; - private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; + private LiftToActivateListener mLiftToActivateListener; + private TelephonyManager mTelephonyManager; private final FalsingCollector mFalsingCollector; private final boolean mIsNewLayoutEnabled; @@ -177,7 +168,6 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor, @Main Resources resources, LiftToActivateListener liftToActivateListener, TelephonyManager telephonyManager, - EmergencyButtonController.Factory emergencyButtonControllerFactory, FalsingCollector falsingCollector, FeatureFlags featureFlags) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -189,7 +179,6 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> mResources = resources; mLiftToActivateListener = liftToActivateListener; mTelephonyManager = telephonyManager; - mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; mFalsingCollector = falsingCollector; mIsNewLayoutEnabled = featureFlags.isKeyguardLayoutEnabled(); } @@ -197,40 +186,31 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView> /** Create a new {@link KeyguardInputViewController}. */ public KeyguardInputViewController create(KeyguardInputView keyguardInputView, SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) { - EmergencyButtonController emergencyButtonController = - mEmergencyButtonControllerFactory.create( - keyguardInputView.findViewById(R.id.emergency_call_button)); - if (keyguardInputView instanceof KeyguardPatternView) { return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, - keyguardSecurityCallback, mLatencyTracker, - emergencyButtonController, - mMessageAreaControllerFactory); + keyguardSecurityCallback, mLatencyTracker, mMessageAreaControllerFactory); } else if (keyguardInputView instanceof KeyguardPasswordView) { return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mInputMethodManager, emergencyButtonController, mMainExecutor, mResources); + mInputMethodManager, mMainExecutor, mResources); } else if (keyguardInputView instanceof KeyguardPINView) { return new KeyguardPinViewController((KeyguardPINView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, - mLiftToActivateListener, emergencyButtonController, mFalsingCollector, - mIsNewLayoutEnabled); + mLiftToActivateListener, mFalsingCollector, mIsNewLayoutEnabled); } else if (keyguardInputView instanceof KeyguardSimPinView) { return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, - emergencyButtonController, mFalsingCollector, mIsNewLayoutEnabled); } else if (keyguardInputView instanceof KeyguardSimPukView) { return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView, mKeyguardUpdateMonitor, securityMode, mLockPatternUtils, keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker, mLiftToActivateListener, mTelephonyManager, - emergencyButtonController, mFalsingCollector, mIsNewLayoutEnabled); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java index 2e4554592580..0f1c3c8a20b7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java @@ -111,11 +111,10 @@ public class KeyguardPasswordViewController KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, InputMethodManager inputMethodManager, - EmergencyButtonController emergencyButtonController, @Main DelayableExecutor mainExecutor, @Main Resources resources) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker, emergencyButtonController); + messageAreaControllerFactory, latencyTracker); mKeyguardSecurityCallback = keyguardSecurityCallback; mInputMethodManager = inputMethodManager; mMainExecutor = mainExecutor; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java index 55e348cc06b1..2aaf748e2415 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java @@ -31,7 +31,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockscreenCredential; -import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback; +import com.android.keyguard.EmergencyButton.EmergencyButtonCallback; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.settingslib.Utils; import com.android.systemui.R; @@ -50,7 +50,6 @@ public class KeyguardPatternViewController private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final LockPatternUtils mLockPatternUtils; private final LatencyTracker mLatencyTracker; - private final EmergencyButtonController mEmergencyButtonController; private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory; private KeyguardMessageAreaController mMessageAreaController; @@ -180,13 +179,11 @@ public class KeyguardPatternViewController LockPatternUtils lockPatternUtils, KeyguardSecurityCallback keyguardSecurityCallback, LatencyTracker latencyTracker, - EmergencyButtonController emergencyButtonController, KeyguardMessageAreaController.Factory messageAreaControllerFactory) { - super(view, securityMode, keyguardSecurityCallback, emergencyButtonController); + super(view, securityMode, keyguardSecurityCallback); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mLockPatternUtils = lockPatternUtils; mLatencyTracker = latencyTracker; - mEmergencyButtonController = emergencyButtonController; mMessageAreaControllerFactory = messageAreaControllerFactory; KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView); mMessageAreaController = mMessageAreaControllerFactory.create(kma); @@ -208,7 +205,11 @@ public class KeyguardPatternViewController KeyguardUpdateMonitor.getCurrentUser())); // vibrate mode will be the same for the life of this screen mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); - mEmergencyButtonController.setEmergencyButtonCallback(mEmergencyButtonCallback); + + EmergencyButton button = mView.findViewById(R.id.emergency_call_button); + if (button != null) { + button.setCallback(mEmergencyButtonCallback); + } View cancelBtn = mView.findViewById(R.id.cancel_button); if (cancelBtn != null) { @@ -223,7 +224,10 @@ public class KeyguardPatternViewController protected void onViewDetached() { super.onViewDetached(); mLockPatternView.setOnPatternListener(null); - mEmergencyButtonController.setEmergencyButtonCallback(null); + EmergencyButton button = mView.findViewById(R.id.emergency_call_button); + if (button != null) { + button.setCallback(null); + } View cancelBtn = mView.findViewById(R.id.cancel_button); if (cancelBtn != null) { cancelBtn.setOnClickListener(null); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java index 1b5aa453ac97..f2479488db0f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java @@ -71,10 +71,9 @@ public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinB KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - EmergencyButtonController emergencyButtonController, FalsingCollector falsingCollector) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, - messageAreaControllerFactory, latencyTracker, emergencyButtonController); + messageAreaControllerFactory, latencyTracker); mLiftToActivateListener = liftToActivateListener; mFalsingCollector = falsingCollector; mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId()); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java index a456d42f5be5..49099fa18323 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java @@ -34,11 +34,10 @@ public class KeyguardPinViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - EmergencyButtonController emergencyButtonController, FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - emergencyButtonController, falsingCollector); + falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; view.setIsNewLayoutEnabled(isNewLayoutEnabled); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java index bacd29f661ae..c77c86711abf 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java @@ -23,6 +23,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.Dependency; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; @@ -48,27 +49,24 @@ public class KeyguardSecurityModel { private final boolean mIsPukScreenAvailable; private final LockPatternUtils mLockPatternUtils; - private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Inject - KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils, - KeyguardUpdateMonitor keyguardUpdateMonitor) { + KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils) { mIsPukScreenAvailable = resources.getBoolean( com.android.internal.R.bool.config_enable_puk_unlock_screen); mLockPatternUtils = lockPatternUtils; - mKeyguardUpdateMonitor = keyguardUpdateMonitor; } public SecurityMode getSecurityMode(int userId) { + KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class); + if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId( - mKeyguardUpdateMonitor.getNextSubIdForState( - TelephonyManager.SIM_STATE_PUK_REQUIRED))) { + monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED))) { return SecurityMode.SimPuk; } if (SubscriptionManager.isValidSubscriptionId( - mKeyguardUpdateMonitor.getNextSubIdForState( - TelephonyManager.SIM_STATE_PIN_REQUIRED))) { + monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED))) { return SecurityMode.SimPin; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java index 33d47fe13f38..f1b504e9f941 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java @@ -44,18 +44,15 @@ public class KeyguardSecurityViewFlipperController private final List<KeyguardInputViewController<KeyguardInputView>> mChildren = new ArrayList<>(); private final LayoutInflater mLayoutInflater; - private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; private final Factory mKeyguardSecurityViewControllerFactory; @Inject protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, LayoutInflater layoutInflater, - KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory, - EmergencyButtonController.Factory emergencyButtonControllerFactory) { + KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) { super(view); mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; mLayoutInflater = layoutInflater; - mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; } @Override @@ -114,8 +111,7 @@ public class KeyguardSecurityViewFlipperController if (childController == null) { childController = new NullKeyguardInputViewController( - securityMode, keyguardSecurityCallback, - mEmergencyButtonControllerFactory.create(null)); + securityMode, keyguardSecurityCallback); } return childController; @@ -144,9 +140,8 @@ public class KeyguardSecurityViewFlipperController private static class NullKeyguardInputViewController extends KeyguardInputViewController<KeyguardInputView> { protected NullKeyguardInputViewController(SecurityMode securityMode, - KeyguardSecurityCallback keyguardSecurityCallback, - EmergencyButtonController emergencyButtonController) { - super(null, securityMode, keyguardSecurityCallback, emergencyButtonController); + KeyguardSecurityCallback keyguardSecurityCallback) { + super(null, securityMode, keyguardSecurityCallback); } @Override diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index 4d2ebbb4a594..cdbbfe643812 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -78,11 +78,11 @@ public class KeyguardSimPinViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager, EmergencyButtonController emergencyButtonController, + TelephonyManager telephonyManager, FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - emergencyButtonController, falsingCollector); + falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java index 0d9bb6f73b49..8fff34278216 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java @@ -37,6 +37,7 @@ import android.widget.ImageView; import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; @@ -84,11 +85,11 @@ public class KeyguardSimPukViewController KeyguardSecurityCallback keyguardSecurityCallback, KeyguardMessageAreaController.Factory messageAreaControllerFactory, LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener, - TelephonyManager telephonyManager, EmergencyButtonController emergencyButtonController, + TelephonyManager telephonyManager, FalsingCollector falsingCollector, boolean isNewLayoutEnabled) { super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback, messageAreaControllerFactory, latencyTracker, liftToActivateListener, - emergencyButtonController, falsingCollector); + falsingCollector); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mTelephonyManager = telephonyManager; mSimImageView = mView.findViewById(R.id.keyguard_sim); @@ -197,7 +198,8 @@ public class KeyguardSimPukViewController if (count < 2) { msg = rez.getString(R.string.kg_puk_enter_puk_hint); } else { - SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId); + SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class) + .getSubscriptionInfoForSubId(mSubId); CharSequence displayName = info != null ? info.getDisplayName() : ""; msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName); if (info != null) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 1fbf71de47ca..fb97a30f93fb 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -49,8 +49,10 @@ import androidx.slice.widget.SliceContent; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.settingslib.Utils; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.wakelock.KeepAwakeAnimationListener; import java.io.FileDescriptor; @@ -315,22 +317,6 @@ public class KeyguardSliceView extends LinearLayout { R.dimen.widget_label_font_size); mRowWithHeaderTextSize = mContext.getResources().getDimensionPixelSize( R.dimen.header_row_font_size); - - for (int i = 0; i < mRow.getChildCount(); i++) { - View child = mRow.getChildAt(i); - if (child instanceof KeyguardSliceTextView) { - ((KeyguardSliceTextView) child).onDensityOrFontScaleChanged(); - } - } - } - - void onOverlayChanged() { - for (int i = 0; i < mRow.getChildCount(); i++) { - View child = mRow.getChildAt(i); - if (child instanceof KeyguardSliceTextView) { - ((KeyguardSliceTextView) child).onOverlayChanged(); - } - } } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -493,7 +479,8 @@ public class KeyguardSliceView extends LinearLayout { * Representation of an item that appears under the clock on main keyguard message. */ @VisibleForTesting - static class KeyguardSliceTextView extends TextView { + static class KeyguardSliceTextView extends TextView implements + ConfigurationController.ConfigurationListener { private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL; @StyleRes @@ -505,10 +492,24 @@ public class KeyguardSliceView extends LinearLayout { setEllipsize(TruncateAt.END); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Dependency.get(ConfigurationController.class).addCallback(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Dependency.get(ConfigurationController.class).removeCallback(this); + } + + @Override public void onDensityOrFontScaleChanged() { updatePadding(); } + @Override public void onOverlayChanged() { setTextAppearance(sStyleId); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java index 8038ce4c7b69..1b0a7faeddab 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -83,10 +83,6 @@ public class KeyguardSliceViewController extends ViewController<KeyguardSliceVie public void onDensityOrFontScaleChanged() { mView.onDensityOrFontScaleChanged(); } - @Override - public void onOverlayChanged() { - mView.onOverlayChanged(); - } }; Observer<Slice> mObserver = new Observer<Slice>() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 5db4f9e61140..fea152abe36a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -34,6 +34,7 @@ import android.widget.TextView; import androidx.core.graphics.ColorUtils; import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.Dependency; import com.android.systemui.R; import java.io.FileDescriptor; @@ -55,6 +56,7 @@ public class KeyguardStatusView extends GridLayout { private final IActivityManager mIActivityManager; private TextView mLogoutView; + private boolean mCanShowLogout = true; // by default, try to show the logout button here private KeyguardClockSwitch mClockView; private TextView mOwnerInfo; private boolean mCanShowOwnerInfo = true; // by default, try to show the owner information here @@ -128,6 +130,11 @@ public class KeyguardStatusView extends GridLayout { } } + void setCanShowLogout(boolean canShowLogout) { + mCanShowLogout = canShowLogout; + updateLogoutView(); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -152,7 +159,10 @@ public class KeyguardStatusView extends GridLayout { mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged); onSliceContentChanged(); + boolean shouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive(); + setEnableMarquee(shouldMarquee); updateOwnerInfo(); + updateLogoutView(); updateDark(); } @@ -199,11 +209,11 @@ public class KeyguardStatusView extends GridLayout { return mOwnerInfo.getVisibility() == VISIBLE ? mOwnerInfo.getHeight() : 0; } - void updateLogoutView(boolean shouldShowLogout) { + void updateLogoutView() { if (mLogoutView == null) { return; } - mLogoutView.setVisibility(shouldShowLogout ? VISIBLE : GONE); + mLogoutView.setVisibility(mCanShowLogout && shouldShowLogout() ? VISIBLE : GONE); // Logout button will stay in language of user 0 if we don't set that manually. mLogoutView.setText(mContext.getResources().getString( com.android.internal.R.string.global_action_logout)); @@ -303,6 +313,11 @@ public class KeyguardStatusView extends GridLayout { } } + private boolean shouldShowLogout() { + return Dependency.get(KeyguardUpdateMonitor.class).isLogoutEnabled() + && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM; + } + private void onLogoutClicked(View view) { int currentUserId = KeyguardUpdateMonitor.getCurrentUser(); try { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index bfe7f8c7ebd8..6fb6760be653 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -16,7 +16,6 @@ package com.android.keyguard; -import android.os.UserHandle; import android.util.Slog; import android.view.View; @@ -79,8 +78,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV @Override public void onInit() { mKeyguardClockSwitchController.init(); - mView.setEnableMarquee(mKeyguardUpdateMonitor.isDeviceInteractive()); - mView.updateLogoutView(shouldShowLogout()); } @Override @@ -248,11 +245,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV } } - private boolean shouldShowLogout() { - return mKeyguardUpdateMonitor.isLogoutEnabled() - && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM; - } - private final ConfigurationController.ConfigurationListener mConfigurationListener = new ConfigurationController.ConfigurationListener() { @Override @@ -279,12 +271,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV mKeyguardSliceViewController.updateTopMargin( mKeyguardClockSwitchController.getClockTextTopPadding()); mView.setCanShowOwnerInfo(false); - mView.updateLogoutView(false); + mView.setCanShowLogout(false); } else { // reset margin mKeyguardSliceViewController.updateTopMargin(0); mView.setCanShowOwnerInfo(true); - mView.updateLogoutView(false); + mView.setCanShowLogout(false); } updateAodIcons(); } @@ -310,7 +302,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing); refreshTime(); mView.updateOwnerInfo(); - mView.updateLogoutView(shouldShowLogout()); + mView.updateLogoutView(); } } @@ -328,12 +320,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV public void onUserSwitchComplete(int userId) { mKeyguardClockSwitchController.refreshFormat(); mView.updateOwnerInfo(); - mView.updateLogoutView(shouldShowLogout()); + mView.updateLogoutView(); } @Override public void onLogoutEnabledChanged() { - mView.updateLogoutView(shouldShowLogout()); + mView.updateLogoutView(); } }; } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java index b6413cb61deb..5ef35be8df51 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockOptionsProvider.java @@ -28,12 +28,11 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.Dependency; import java.io.FileNotFoundException; import java.util.List; - -import javax.inject.Inject; -import javax.inject.Provider; +import java.util.function.Supplier; /** * Exposes custom clock face options and provides realistic preview images. @@ -66,12 +65,15 @@ public final class ClockOptionsProvider extends ContentProvider { private static final String CONTENT_SCHEME = "content"; private static final String AUTHORITY = "com.android.keyguard.clock"; - @Inject - public Provider<List<ClockInfo>> mClockInfosProvider; + private final Supplier<List<ClockInfo>> mClocksSupplier; + + public ClockOptionsProvider() { + this(() -> Dependency.get(ClockManager.class).getClockInfos()); + } @VisibleForTesting - ClockOptionsProvider(Provider<List<ClockInfo>> clockInfosProvider) { - mClockInfosProvider = clockInfosProvider; + ClockOptionsProvider(Supplier<List<ClockInfo>> clocksSupplier) { + mClocksSupplier = clocksSupplier; } @Override @@ -97,7 +99,7 @@ public final class ClockOptionsProvider extends ContentProvider { } MatrixCursor cursor = new MatrixCursor(new String[] { COLUMN_NAME, COLUMN_TITLE, COLUMN_ID, COLUMN_THUMBNAIL, COLUMN_PREVIEW}); - List<ClockInfo> clocks = mClockInfosProvider.get(); + List<ClockInfo> clocks = mClocksSupplier.get(); for (int i = 0; i < clocks.size(); i++) { ClockInfo clock = clocks.get(i); cursor.newRow() @@ -137,7 +139,7 @@ public final class ClockOptionsProvider extends ContentProvider { throw new FileNotFoundException("Invalid preview url, missing id"); } ClockInfo clock = null; - List<ClockInfo> clocks = mClockInfosProvider.get(); + List<ClockInfo> clocks = mClocksSupplier.get(); for (int i = 0; i < clocks.size(); i++) { if (id.equals(clocks.get(i).getId())) { clock = clocks.get(i); diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java deleted file mode 100644 index 49a617eeb6c0..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.keyguard.dagger; - -import com.android.keyguard.KeyguardStatusViewController; -import com.android.systemui.statusbar.phone.KeyguardStatusBarView; -import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController; - -import dagger.BindsInstance; -import dagger.Subcomponent; - -/** - * Subcomponent for helping work with KeyguardStatusView and its children. - * - * TODO: unify this with {@link KeyguardStatusViewComponent} - */ -@Subcomponent(modules = {KeyguardStatusBarViewModule.class}) -@KeyguardStatusBarViewScope -public interface KeyguardStatusBarViewComponent { - /** Simple factory for {@link KeyguardStatusBarViewComponent}. */ - @Subcomponent.Factory - interface Factory { - KeyguardStatusBarViewComponent build(@BindsInstance KeyguardStatusBarView view); - } - - /** Builds a {@link KeyguardStatusViewController}. */ - KeyguardStatusBarViewController getKeyguardStatusBarViewController(); -} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java deleted file mode 100644 index a6725234e4af..000000000000 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.keyguard.dagger; - -import com.android.keyguard.CarrierText; -import com.android.systemui.R; -import com.android.systemui.statusbar.phone.KeyguardStatusBarView; - -import dagger.Module; -import dagger.Provides; - -/** Dagger module for {@link KeyguardStatusBarViewComponent}. */ -@Module -public abstract class KeyguardStatusBarViewModule { - @Provides - @KeyguardStatusBarViewScope - static CarrierText getCarrierText(KeyguardStatusBarView view) { - return view.findViewById(R.id.keyguard_carrier_text); - } -} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java index d342377da49b..1b6476ce74df 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java @@ -25,8 +25,6 @@ import dagger.Subcomponent; /** * Subcomponent for helping work with KeyguardStatusView and its children. - * - * TODO: unify this with {@link KeyguardStatusBarViewComponent} */ @Subcomponent(modules = {KeyguardStatusViewModule.class}) @KeyguardStatusViewScope diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 91c2dcfd9202..ffb8446f3e21 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -16,7 +16,6 @@ package com.android.systemui.dagger; -import com.android.keyguard.clock.ClockOptionsProvider; import com.android.systemui.BootCompleteCacheImpl; import com.android.systemui.Dependency; import com.android.systemui.InitController; @@ -147,9 +146,4 @@ public interface SysUIComponent { * Member injection into the supplied argument. */ void inject(KeyguardSliceProvider keyguardSliceProvider); - - /** - * Member injection into the supplied argument. - */ - void inject(ClockOptionsProvider clockOptionsProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index b67db03a743c..b0067cd15c1b 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -22,7 +22,6 @@ import android.content.Context; import androidx.annotation.Nullable; import com.android.internal.statusbar.IStatusBarService; -import com.android.keyguard.clock.ClockModule; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.BootCompleteCache; import com.android.systemui.BootCompleteCacheImpl; @@ -91,7 +90,6 @@ import dagger.Provides; @Module(includes = { AppOpsModule.class, AssistModule.class, - ClockModule.class, ControlsModule.class, DemoModeModule.class, FalsingModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index 5c8c9f22d585..8ab135ced97e 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -23,6 +23,7 @@ import android.app.AlarmManager; import android.content.Context; import android.os.Handler; import android.os.SystemClock; +import android.provider.Settings; import android.text.format.Formatter; import android.util.Log; @@ -32,6 +33,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.tuner.TunerService; import com.android.systemui.util.AlarmTimeout; import com.android.systemui.util.wakelock.WakeLock; @@ -43,7 +45,7 @@ import javax.inject.Inject; * The policy controlling doze. */ @DozeScope -public class DozeUi implements DozeMachine.Part { +public class DozeUi implements DozeMachine.Part, TunerService.Tunable { private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min private final Context mContext; @@ -73,7 +75,7 @@ public class DozeUi implements DozeMachine.Part { public DozeUi(Context context, AlarmManager alarmManager, WakeLock wakeLock, DozeHost host, @Main Handler handler, DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor, - DozeLog dozeLog) { + DozeLog dozeLog, TunerService tunerService) { mContext = context; mWakeLock = wakeLock; mHost = host; @@ -83,6 +85,8 @@ public class DozeUi implements DozeMachine.Part { mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler); keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback); mDozeLog = dozeLog; + + tunerService.addTunable(this, Settings.Secure.DOZE_ALWAYS_ON); } @Override @@ -238,4 +242,11 @@ public class DozeUi implements DozeMachine.Part { KeyguardUpdateMonitorCallback getKeyguardCallback() { return mKeyguardVisibilityCallback; } + + @Override + public void onTuningChanged(String key, String newValue) { + if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) { + updateAnimateScreenOff(); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java index b77fcc822b88..073586e88a8b 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java @@ -16,24 +16,18 @@ package com.android.systemui.flags; -import android.annotation.NonNull; import android.content.res.Resources; -import android.provider.DeviceConfig; import android.util.SparseArray; import androidx.annotation.BoolRes; import androidx.annotation.Nullable; import com.android.systemui.R; -import com.android.systemui.assist.DeviceConfigHelper; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.wrapper.BuildInfo; -import java.util.concurrent.Executor; - import javax.inject.Inject; /** * Reads and caches feature flags for quick access @@ -60,23 +54,19 @@ import javax.inject.Inject; @SysUISingleton public class FeatureFlagReader { private final Resources mResources; - private final DeviceConfigHelper mDeviceConfig; private final boolean mAreFlagsOverrideable; - + private final SystemPropertiesHelper mSystemPropertiesHelper; private final SparseArray<CachedFlag> mCachedFlags = new SparseArray<>(); @Inject public FeatureFlagReader( @Main Resources resources, BuildInfo build, - DeviceConfigHelper deviceConfig, - @Background Executor executor) { + SystemPropertiesHelper systemPropertiesHelper) { mResources = resources; - mDeviceConfig = deviceConfig; + mSystemPropertiesHelper = systemPropertiesHelper; mAreFlagsOverrideable = build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable); - - mDeviceConfig.addOnPropertiesChangedListener(executor, this::onPropertiesChanged); } /** @@ -93,7 +83,7 @@ public class FeatureFlagReader { String name = resourceIdToFlagName(resId); boolean value = mResources.getBoolean(resId); if (mAreFlagsOverrideable) { - value = mDeviceConfig.getBoolean(flagNameToStorageKey(name), value); + value = mSystemPropertiesHelper.getBoolean(flagNameToStorageKey(name), value); } cachedFlag = new CachedFlag(name, value); @@ -104,27 +94,6 @@ public class FeatureFlagReader { } } - private void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { - synchronized (mCachedFlags) { - for (String key : properties.getKeyset()) { - String flagName = storageKeyToFlagName(key); - if (flagName != null) { - clearCachedFlag(flagName); - } - } - } - } - - private void clearCachedFlag(String flagName) { - for (int i = 0; i < mCachedFlags.size(); i++) { - CachedFlag flag = mCachedFlags.valueAt(i); - if (flag.name.equals(flagName)) { - mCachedFlags.removeAt(i); - break; - } - } - } - private String resourceIdToFlagName(@BoolRes int resId) { String resName = mResources.getResourceEntryName(resId); if (resName.startsWith(RESNAME_PREFIX)) { @@ -160,6 +129,6 @@ public class FeatureFlagReader { } } - private static final String STORAGE_KEY_PREFIX = "flag_"; + private static final String STORAGE_KEY_PREFIX = "persist.systemui.flag_"; private static final String RESNAME_PREFIX = "flag_"; } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt index ba0642f57a88..28f63b07e584 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java +++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,19 +14,19 @@ * limitations under the License. */ -package com.android.keyguard.dagger; +package com.android.systemui.flags -import static java.lang.annotation.RetentionPolicy.RUNTIME; +import android.os.SystemProperties +import com.android.systemui.dagger.SysUISingleton -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -import javax.inject.Scope; +import javax.inject.Inject /** - * Scope annotation for singleton items within the StatusBarComponent. + * Proxy to make {@link SystemProperties} easily testable. */ -@Documented -@Retention(RUNTIME) -@Scope -public @interface KeyguardStatusBarViewScope {} +@SysUISingleton +class SystemPropertiesHelper @Inject constructor() { + fun getBoolean(name: String, default: Boolean): Boolean { + return SystemProperties.getBoolean(name, default) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 91cf7108c728..eef41e045948 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2395,6 +2395,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, return; } mDozing = dozing; + if (!dozing) { + mAnimatingScreenOff = false; + } setShowingLocked(mShowing); } @@ -2404,7 +2407,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, // is 1f), then show the activity lock screen. if (mAnimatingScreenOff && mDozing && linear == 1f) { mAnimatingScreenOff = false; - setShowingLocked(mShowing); + setShowingLocked(mShowing, true); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index a747edd0580a..de2e7c476e18 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -30,7 +30,6 @@ import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardViewController; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; -import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -64,11 +63,8 @@ import dagger.Provides; /** * Dagger Module providing {@link StatusBar}. */ -@Module(subcomponents = { - KeyguardQsUserSwitchComponent.class, - KeyguardStatusBarViewComponent.class, - KeyguardStatusViewComponent.class, - KeyguardUserSwitcherComponent.class}, +@Module(subcomponents = {KeyguardStatusViewComponent.class, + KeyguardQsUserSwitchComponent.class, KeyguardUserSwitcherComponent.class}, includes = {FalsingModule.class}) public class KeyguardModule { /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java index aa6bbbda04fb..a567f512b204 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java @@ -34,7 +34,7 @@ import android.widget.TextView; import androidx.annotation.VisibleForTesting; -import com.android.keyguard.CarrierTextManager; +import com.android.keyguard.CarrierTextController; import com.android.settingslib.AccessibilityContentDescriptions; import com.android.settingslib.mobile.TelephonyIcons; import com.android.systemui.R; @@ -58,7 +58,7 @@ public class QSCarrierGroupController { private final ActivityStarter mActivityStarter; private final Handler mBgHandler; private final NetworkController mNetworkController; - private final CarrierTextManager mCarrierTextManager; + private final CarrierTextController mCarrierTextController; private final TextView mNoSimTextView; private final H mMainHandler; private final Callback mCallback; @@ -153,7 +153,7 @@ public class QSCarrierGroupController { } }; - private static class Callback implements CarrierTextManager.CarrierTextCallback { + private static class Callback implements CarrierTextController.CarrierTextCallback { private H mHandler; Callback(H handler) { @@ -161,7 +161,7 @@ public class QSCarrierGroupController { } @Override - public void updateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { + public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { mHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget(); } } @@ -169,7 +169,7 @@ public class QSCarrierGroupController { private QSCarrierGroupController(QSCarrierGroup view, ActivityStarter activityStarter, @Background Handler bgHandler, @Main Looper mainLooper, NetworkController networkController, - CarrierTextManager.Builder carrierTextManagerBuilder, Context context) { + CarrierTextController.Builder carrierTextControllerBuilder, Context context) { if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) { mProviderModel = true; } else { @@ -178,7 +178,7 @@ public class QSCarrierGroupController { mActivityStarter = activityStarter; mBgHandler = bgHandler; mNetworkController = networkController; - mCarrierTextManager = carrierTextManagerBuilder + mCarrierTextController = carrierTextControllerBuilder .setShowAirplaneMode(false) .setShowMissingSim(false) .build(); @@ -196,6 +196,7 @@ public class QSCarrierGroupController { mMainHandler = new H(mainLooper, this::handleUpdateCarrierInfo, this::handleUpdateState); mCallback = new Callback(mMainHandler); + mCarrierGroups[0] = view.getCarrier1View(); mCarrierGroups[1] = view.getCarrier2View(); mCarrierGroups[2] = view.getCarrier3View(); @@ -246,10 +247,10 @@ public class QSCarrierGroupController { if (mNetworkController.hasVoiceCallingFeature()) { mNetworkController.addCallback(mSignalCallback); } - mCarrierTextManager.setListening(mCallback); + mCarrierTextController.setListening(mCallback); } else { mNetworkController.removeCallback(mSignalCallback); - mCarrierTextManager.setListening(null); + mCarrierTextController.setListening(null); } } @@ -276,7 +277,7 @@ public class QSCarrierGroupController { } @MainThread - private void handleUpdateCarrierInfo(CarrierTextManager.CarrierTextCallbackInfo info) { + private void handleUpdateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) { if (!mMainHandler.getLooper().isCurrentThread()) { mMainHandler.obtainMessage(H.MSG_UPDATE_CARRIER_INFO, info).sendToTarget(); return; @@ -330,13 +331,13 @@ public class QSCarrierGroupController { } private static class H extends Handler { - private Consumer<CarrierTextManager.CarrierTextCallbackInfo> mUpdateCarrierInfo; + private Consumer<CarrierTextController.CarrierTextCallbackInfo> mUpdateCarrierInfo; private Runnable mUpdateState; static final int MSG_UPDATE_CARRIER_INFO = 0; static final int MSG_UPDATE_STATE = 1; H(Looper looper, - Consumer<CarrierTextManager.CarrierTextCallbackInfo> updateCarrierInfo, + Consumer<CarrierTextController.CarrierTextCallbackInfo> updateCarrierInfo, Runnable updateState) { super(looper); mUpdateCarrierInfo = updateCarrierInfo; @@ -348,7 +349,7 @@ public class QSCarrierGroupController { switch (msg.what) { case MSG_UPDATE_CARRIER_INFO: mUpdateCarrierInfo.accept( - (CarrierTextManager.CarrierTextCallbackInfo) msg.obj); + (CarrierTextController.CarrierTextCallbackInfo) msg.obj); break; case MSG_UPDATE_STATE: mUpdateState.run(); @@ -365,13 +366,13 @@ public class QSCarrierGroupController { private final Handler mHandler; private final Looper mLooper; private final NetworkController mNetworkController; - private final CarrierTextManager.Builder mCarrierTextControllerBuilder; + private final CarrierTextController.Builder mCarrierTextControllerBuilder; private final Context mContext; @Inject public Builder(ActivityStarter activityStarter, @Background Handler handler, @Main Looper looper, NetworkController networkController, - CarrierTextManager.Builder carrierTextControllerBuilder, Context context) { + CarrierTextController.Builder carrierTextControllerBuilder, Context context) { mActivityStarter = activityStarter; mHandler = handler; mLooper = looper; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index e391250dc8fd..50cbbd5d4852 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -264,6 +264,20 @@ class NotificationWakeUpCoordinator @Inject constructor( } override fun onStateChanged(newState: Int) { + if (dozeParameters.shouldControlUnlockedScreenOff()) { + if (animatingScreenOff && + state == StatusBarState.KEYGUARD && + newState == StatusBarState.SHADE) { + // If we're animating the screen off and going from KEYGUARD back to SHADE, the + // animation was cancelled and we are unlocking. Override the doze amount to 0f (not + // dozing) so that the notifications are no longer hidden. + setDozeAmount(0f, 0f) + } + + animatingScreenOff = + state == StatusBarState.SHADE && newState == StatusBarState.KEYGUARD + } + overrideDozeAmountIfBypass() if (bypassController.bypassEnabled && newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED && @@ -273,13 +287,6 @@ class NotificationWakeUpCoordinator @Inject constructor( setNotificationsVisible(visible = false, increaseSpeed = false, animate = true) } - // If we want to control the screen off animation, check whether we are going from SHADE to - // KEYGUARD. - if (dozeParameters.shouldControlUnlockedScreenOff()) { - animatingScreenOff = - state == StatusBarState.SHADE && newState == StatusBarState.KEYGUARD - } - this.state = newState } @@ -386,8 +393,6 @@ class NotificationWakeUpCoordinator @Inject constructor( override fun onDozingChanged(isDozing: Boolean) { if (isDozing) { setNotificationsVisible(visible = false, animate = false, increaseSpeed = false) - } else { - animatingScreenOff = false } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java deleted file mode 100644 index 377fb92ac6ba..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import com.android.keyguard.CarrierTextController; -import com.android.systemui.util.ViewController; - -import javax.inject.Inject; - -/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */ -public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> { - private final CarrierTextController mCarrierTextController; - - @Inject - public KeyguardStatusBarViewController( - KeyguardStatusBarView view, CarrierTextController carrierTextController) { - super(view); - mCarrierTextController = carrierTextController; - } - - @Override - protected void onInit() { - super.onInit(); - mCarrierTextController.init(); - } - - @Override - protected void onViewAttached() { - } - - @Override - protected void onViewDetached() { - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 2f9fa9e6ec41..0b3fd161d865 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -83,7 +83,6 @@ import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; -import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; @@ -326,7 +325,6 @@ public class NotificationPanelViewController extends PanelViewController { private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory; private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory; - private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; private final QSDetailDisplayer mQSDetailDisplayer; private final FeatureFlags mFeatureFlags; private final ScrimController mScrimController; @@ -343,7 +341,6 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mKeyguardUserSwitcherIsShowing; private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarView mKeyguardStatusBar; - private KeyguardStatusBarViewController mKeyguarStatusBarViewController; private ViewGroup mBigClockContainer; private QS mQs; private FrameLayout mQsFrame; @@ -597,7 +594,6 @@ public class NotificationPanelViewController extends PanelViewController { KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory, KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory, KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory, - KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory, QSDetailDisplayer qsDetailDisplayer, NotificationGroupManagerLegacy groupManager, NotificationIconAreaController notificationIconAreaController, @@ -624,7 +620,6 @@ public class NotificationPanelViewController extends PanelViewController { mGroupManager = groupManager; mNotificationIconAreaController = notificationIconAreaController; mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory; - mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory; mFeatureFlags = featureFlags; mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory; mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory; @@ -728,9 +723,7 @@ public class NotificationPanelViewController extends PanelViewController { } updateViewControllers(mView.findViewById(R.id.keyguard_status_view), - userAvatarView, - mKeyguardStatusBar, - keyguardUserSwitcherView); + userAvatarView, keyguardUserSwitcherView); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); NotificationStackScrollLayout stackScrollLayout = mView.findViewById( R.id.notification_stack_scroller); @@ -808,21 +801,13 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateViewControllers(KeyguardStatusView keyguardStatusView, - UserAvatarView userAvatarView, - KeyguardStatusBarView keyguardStatusBarView, - KeyguardUserSwitcherView keyguardUserSwitcherView) { + UserAvatarView userAvatarView, KeyguardUserSwitcherView keyguardUserSwitcherView) { // Re-associate the KeyguardStatusViewController KeyguardStatusViewComponent statusViewComponent = mKeyguardStatusViewComponentFactory.build(keyguardStatusView); mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController(); mKeyguardStatusViewController.init(); - KeyguardStatusBarViewComponent statusBarViewComponent = - mKeyguardStatusBarViewComponentFactory.build(keyguardStatusBarView); - mKeyguarStatusBarViewController = - statusBarViewComponent.getKeyguardStatusBarViewController(); - mKeyguarStatusBarViewController.init(); - // Re-associate the clock container with the keyguard clock switch. KeyguardClockSwitchController keyguardClockSwitchController = statusViewComponent.getKeyguardClockSwitchController(); @@ -970,8 +955,7 @@ public class NotificationPanelViewController extends PanelViewController { showKeyguardUserSwitcher /* enabled */); mBigClockContainer.removeAllViews(); - updateViewControllers( - keyguardStatusView, userAvatarView, mKeyguardStatusBar, keyguardUserSwitcherView); + updateViewControllers(keyguardStatusView, userAvatarView, keyguardUserSwitcherView); // Update keyguard bottom area index = mView.indexOfChild(mKeyguardBottomArea); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index d3f9d641ca9f..aa4122fd190a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -54,6 +54,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.text.TextUtils; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.WakefulnessLifecycle; @@ -73,7 +74,7 @@ import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -public class CarrierTextManagerTest extends SysuiTestCase { +public class CarrierTextControllerTest extends SysuiTestCase { private static final CharSequence SEPARATOR = " \u2014 "; private static final CharSequence INVALID_CARD_TEXT = "Invalid card"; @@ -94,9 +95,7 @@ public class CarrierTextManagerTest extends SysuiTestCase { @Mock private WifiManager mWifiManager; @Mock - private WakefulnessLifecycle mWakefulnessLifecycle; - @Mock - private CarrierTextManager.CarrierTextCallback mCarrierTextCallback; + private CarrierTextController.CarrierTextCallback mCarrierTextCallback; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock @@ -105,14 +104,13 @@ public class CarrierTextManagerTest extends SysuiTestCase { private TelephonyManager mTelephonyManager; @Mock private SubscriptionManager mSubscriptionManager; - private CarrierTextManager.CarrierTextCallbackInfo mCarrierTextCallbackInfo; + private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo; - private CarrierTextManager mCarrierTextManager; + private CarrierTextController mCarrierTextController; private TestableLooper mTestableLooper; - private Handler mMainHandler; private Void checkMainThread(InvocationOnMock inv) { - Looper mainLooper = mMainHandler.getLooper(); + Looper mainLooper = Dependency.get(Dependency.MAIN_HANDLER).getLooper(); if (!mainLooper.isCurrentThread()) { fail("This call should be done from the main thread"); } @@ -124,33 +122,35 @@ public class CarrierTextManagerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); - mMainHandler = new Handler(mTestableLooper.getLooper()); + mContext.addMockSystemService(WifiManager.class, mWifiManager); + mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager); when(mConnectivityManager.isNetworkSupported(anyInt())).thenReturn(true); + mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager); + mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); mContext.getOrCreateTestableResources().addOverride( R.string.keyguard_sim_error_message_short, INVALID_CARD_TEXT); mContext.getOrCreateTestableResources().addOverride( R.string.airplane_mode, AIRPLANE_MODE_TEXT); + mDependency.injectMockDependency(WakefulnessLifecycle.class); + mDependency.injectTestDependency(Dependency.MAIN_HANDLER, + new Handler(mTestableLooper.getLooper())); + mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); + mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor); doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor) .registerCallback(any(KeyguardUpdateMonitorCallback.class)); doAnswer(this::checkMainThread).when(mKeyguardUpdateMonitor) .removeCallback(any(KeyguardUpdateMonitorCallback.class)); - mCarrierTextCallbackInfo = new CarrierTextManager.CarrierTextCallbackInfo("", + mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("", new CharSequence[]{}, false, new int[]{}); when(mTelephonyManager.getSupportedModemCount()).thenReturn(3); when(mTelephonyManager.getActiveModemCount()).thenReturn(3); - mCarrierTextManager = new CarrierTextManager.Builder( - mContext, mContext.getResources(), mWifiManager, mConnectivityManager, - mTelephonyManager, mWakefulnessLifecycle, new Handler(mTestableLooper.getLooper()), - mMainHandler, mKeyguardUpdateMonitor) - .setShowAirplaneMode(true) - .setShowMissingSim(true) - .build(); + mCarrierTextController = new CarrierTextController(mContext, SEPARATOR, true, true); // This should not start listening on any of the real dependencies but will test that // callbacks in mKeyguardUpdateMonitor are done in the mTestableLooper thread - mCarrierTextManager.setListening(mCarrierTextCallback); + mCarrierTextController.setListening(mCarrierTextCallback); mTestableLooper.processAllMessages(); } @@ -165,8 +165,8 @@ public class CarrierTextManagerTest extends SysuiTestCase { TestableLooper testableLooper = new TestableLooper(thread.getLooper()); Handler h = new Handler(testableLooper.getLooper()); h.post(() -> { - mCarrierTextManager.setListening(null); - mCarrierTextManager.setListening(mCarrierTextCallback); + mCarrierTextController.setListening(null); + mCarrierTextController.setListening(mCarrierTextCallback); }); testableLooper.processAllMessages(); mTestableLooper.processAllMessages(); @@ -183,11 +183,11 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -205,12 +205,12 @@ public class CarrierTextManagerTest extends SysuiTestCase { TelephonyManager.SIM_STATE_CARD_IO_ERROR); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - mCarrierTextManager.mCallback.onSimStateChanged(3, 1, + mCarrierTextController.mCallback.onSimStateChanged(3, 1, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -223,7 +223,7 @@ public class CarrierTextManagerTest extends SysuiTestCase { reset(mCarrierTextCallback); when(mTelephonyManager.getActiveModemCount()).thenReturn(1); // Update carrier text. It should ignore error state of subId 3 in inactive slotId. - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals("TEST_CARRIER", captor.getValue().carrierText); @@ -237,9 +237,9 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( TelephonyManager.SIM_STATE_CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions - mCarrierTextManager.mCallback.onSimStateChanged(0, -3, + mCarrierTextController.mCallback.onSimStateChanged(0, -3, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - mCarrierTextManager.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY); + mCarrierTextController.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY); verify(mCarrierTextCallback, never()).updateCarrierInfo(any()); } @@ -257,23 +257,23 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( TelephonyManager.SIM_STATE_CARD_IO_ERROR); // This should not produce an out of bounds error, even though there are no subscriptions - mCarrierTextManager.mCallback.onSimStateChanged(0, 1, + mCarrierTextController.mCallback.onSimStateChanged(0, 1, TelephonyManager.SIM_STATE_CARD_IO_ERROR); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo( - any(CarrierTextManager.CarrierTextCallbackInfo.class)); + any(CarrierTextController.CarrierTextCallbackInfo.class)); } @Test public void testCallback() { reset(mCarrierTextCallback); - mCarrierTextManager.postToCallback(mCarrierTextCallbackInfo); + mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); mTestableLooper.processAllMessages(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); assertEquals(mCarrierTextCallbackInfo, captor.getValue()); } @@ -282,8 +282,8 @@ public class CarrierTextManagerTest extends SysuiTestCase { public void testNullingCallback() { reset(mCarrierTextCallback); - mCarrierTextManager.postToCallback(mCarrierTextCallbackInfo); - mCarrierTextManager.setListening(null); + mCarrierTextController.postToCallback(mCarrierTextCallbackInfo); + mCarrierTextController.setListening(null); // This shouldn't produce NPE mTestableLooper.processAllMessages(); @@ -301,15 +301,15 @@ public class CarrierTextManagerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertEquals(TEST_CARRIER, info.listOfCarriers[0]); assertEquals(1, info.subscriptionIds.length); @@ -326,15 +326,15 @@ public class CarrierTextManagerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(1, info.listOfCarriers.length); assertTrue(info.listOfCarriers[0].toString().contains(TEST_CARRIER)); assertEquals(1, info.subscriptionIds.length); @@ -346,16 +346,16 @@ public class CarrierTextManagerTest extends SysuiTestCase { List<SubscriptionInfo> list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION_NULL); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( - TelephonyManager.SIM_STATE_READY); + TelephonyManager.SIM_STATE_READY); when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -380,11 +380,11 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(ss.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE); mKeyguardUpdateMonitor.mServiceStates.put(TEST_SUBSCRIPTION_NULL.getSubscriptionId(), ss); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -407,15 +407,15 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - CarrierTextManager.CarrierTextCallbackInfo info = captor.getValue(); + CarrierTextController.CarrierTextCallbackInfo info = captor.getValue(); assertEquals(0, info.listOfCarriers.length); assertEquals(0, info.subscriptionIds.length); @@ -428,16 +428,16 @@ public class CarrierTextManagerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION); list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( - TelephonyManager.SIM_STATE_READY); + TelephonyManager.SIM_STATE_READY); when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -458,11 +458,11 @@ public class CarrierTextManagerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -483,11 +483,11 @@ public class CarrierTextManagerTest extends SysuiTestCase { mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); @@ -509,11 +509,11 @@ public class CarrierTextManagerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor = + ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor = ArgumentCaptor.forClass( - CarrierTextManager.CarrierTextCallbackInfo.class); + CarrierTextController.CarrierTextCallbackInfo.class); - mCarrierTextManager.updateCarrierText(); + mCarrierTextController.updateCarrierText(); mTestableLooper.processAllMessages(); verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java index d67fe6dfb0b2..c2ade81a9877 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java @@ -69,8 +69,6 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { private KeyguardMessageAreaController mKeyguardMessageAreaController; @Mock private LatencyTracker mLatencyTracker; - @Mock - private EmergencyButtonController mEmergencyButtonController; private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; @@ -86,8 +84,7 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { .thenReturn(mKeyguardMessageArea); mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mKeyguardMessageAreaControllerFactory, mLatencyTracker, - mEmergencyButtonController) { + mKeyguardMessageAreaControllerFactory, mLatencyTracker) { @Override void resetState() { } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java index 4beec574cd2a..826be2ba0d83 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java @@ -54,11 +54,11 @@ import java.util.concurrent.Executor; public class KeyguardDisplayManagerTest extends SysuiTestCase { @Mock - private NavigationBarController mNavigationBarController; - @Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory; + @Mock private DisplayManager mDisplayManager; + @Mock private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation; @@ -76,8 +76,9 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mContext.addMockSystemService(DisplayManager.class, mDisplayManager); - mManager = spy(new KeyguardDisplayManager(mContext, () -> mNavigationBarController, - mKeyguardStatusViewComponentFactory, mBackgroundExecutor)); + mDependency.injectMockDependency(NavigationBarController.class); + mManager = spy(new KeyguardDisplayManager(mContext, mKeyguardStatusViewComponentFactory, + mBackgroundExecutor)); doReturn(mKeyguardPresentation).when(mManager).createPresentation(any()); mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY, diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt index 6d0c64088abc..c69ec1a254c3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt @@ -49,8 +49,6 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { @Mock private lateinit var mLatencyTracker: LatencyTracker @Mock - private lateinit var mEmergencyButtonController: EmergencyButtonController - @Mock private lateinit var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory @Mock @@ -74,8 +72,7 @@ class KeyguardPatternViewControllerTest : SysuiTestCase() { .thenReturn(mKeyguardMessageAreaController) mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, - mLatencyTracker, mEmergencyButtonController, - mKeyguardMessageAreaControllerFactory) + mLatencyTracker, mKeyguardMessageAreaControllerFactory) } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java index 8d1e1a4a4463..31cc7bb7c958 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java @@ -67,8 +67,6 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { private LatencyTracker mLatencyTracker; @Mock private LiftToActivateListener mLiftToactivateListener; - @Mock - private EmergencyButtonController mEmergencyButtonController; private FalsingCollector mFalsingCollector = new FalsingCollectorFake(); @Mock private View mDeleteButton; @@ -94,7 +92,7 @@ public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase { mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView, mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener, - mEmergencyButtonController, mFalsingCollector) { + mFalsingCollector) { @Override public void onResume(int reason) { super.onResume(reason); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java index 9296d3d5ec82..3b7f4b839853 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java @@ -59,10 +59,6 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { @Mock private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory; @Mock - private EmergencyButtonController.Factory mEmergencyButtonControllerFactory; - @Mock - private EmergencyButtonController mEmergencyButtonController; - @Mock private KeyguardInputViewController mKeyguardInputViewController; @Mock private KeyguardInputView mInputView; @@ -80,12 +76,9 @@ public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase { any(KeyguardSecurityCallback.class))) .thenReturn(mKeyguardInputViewController); when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController); - when(mEmergencyButtonControllerFactory.create(any(EmergencyButton.class))) - .thenReturn(mEmergencyButtonController); mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView, - mLayoutInflater, mKeyguardSecurityViewControllerFactory, - mEmergencyButtonControllerFactory); + mLayoutInflater, mKeyguardSecurityViewControllerFactory); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java index 6d8c372a061b..d60772730dff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java @@ -42,6 +42,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.tuner.TunerService; import com.android.systemui.util.wakelock.WakeLockFake; import org.junit.After; @@ -67,6 +68,8 @@ public class DozeUiTest extends SysuiTestCase { private DozeHost mHost; @Mock private DozeLog mDozeLog; + @Mock + private TunerService mTunerService; private WakeLockFake mWakeLock; private Handler mHandler; private HandlerThread mHandlerThread; @@ -82,7 +85,7 @@ public class DozeUiTest extends SysuiTestCase { mHandler = mHandlerThread.getThreadHandler(); mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler, - mDozeParameters, mKeyguardUpdateMonitor, mDozeLog); + mDozeParameters, mKeyguardUpdateMonitor, mDozeLog, mTunerService); mDozeUi.setDozeMachine(mMachine); } @@ -138,7 +141,7 @@ public class DozeUiTest extends SysuiTestCase { reset(mHost); when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true); mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler, - mDozeParameters, mKeyguardUpdateMonitor, mDozeLog); + mDozeParameters, mKeyguardUpdateMonitor, mDozeLog, mTunerService); mDozeUi.setDozeMachine(mMachine); // Never animate if display doesn't support it. diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java index c79037b761aa..223714cfda30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java @@ -18,7 +18,6 @@ package com.android.systemui.flags; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -27,59 +26,44 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.res.Resources; -import android.provider.DeviceConfig; import androidx.annotation.BoolRes; import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.assist.DeviceConfigHelper; import com.android.systemui.util.wrapper.BuildInfo; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Executor; - @SmallTest public class FeatureFlagReaderTest extends SysuiTestCase { @Mock private Resources mResources; @Mock private BuildInfo mBuildInfo; - @Mock private DeviceConfigHelper mDeviceConfig; - @Mock private Executor mBackgroundExecutor; + @Mock private SystemPropertiesHelper mSystemPropertiesHelper; private FeatureFlagReader mReader; - @Captor private ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener> mListenerCaptor; - private DeviceConfig.OnPropertiesChangedListener mPropChangeListener; - @Before public void setUp() { MockitoAnnotations.initMocks(this); - when(mDeviceConfig.getBoolean(anyString(), anyBoolean())) + when(mSystemPropertiesHelper.getBoolean(anyString(), anyBoolean())) .thenAnswer(invocation -> invocation.getArgument(1)); defineFlag(FLAG_RESID_0, false); defineFlag(FLAG_RESID_1, true); initialize(true, true); - - verify(mDeviceConfig).addOnPropertiesChangedListener(any(), mListenerCaptor.capture()); - mPropChangeListener = mListenerCaptor.getValue(); } private void initialize(boolean isDebuggable, boolean isOverrideable) { when(mBuildInfo.isDebuggable()).thenReturn(isDebuggable); when(mResources.getBoolean(R.bool.are_flags_overrideable)).thenReturn(isOverrideable); - mReader = new FeatureFlagReader(mResources, mBuildInfo, mDeviceConfig, mBackgroundExecutor); + mReader = new FeatureFlagReader(mResources, mBuildInfo, mSystemPropertiesHelper); } @Test @@ -136,24 +120,8 @@ public class FeatureFlagReaderTest extends SysuiTestCase { // THEN the underlying resource and override are only queried once verify(mResources, times(1)).getBoolean(FLAG_RESID_0); - verify(mDeviceConfig, times(1)).getBoolean(fakeStorageKey(FLAG_RESID_0), false); - } - - @Test - public void testCachesAreClearedAfterPropsChange() { - // GIVEN a flag whose value has already been queried - assertFalse(mReader.isEnabled(FLAG_RESID_0)); - - // WHEN the value of the flag changes - overrideFlag(FLAG_RESID_0, true); - Map<String, String> changedMap = new HashMap<>(); - changedMap.put(fakeStorageKey(FLAG_RESID_0), "true"); - DeviceConfig.Properties properties = - new DeviceConfig.Properties("systemui", changedMap); - mPropChangeListener.onPropertiesChanged(properties); - - // THEN the new value is provided - assertTrue(mReader.isEnabled(FLAG_RESID_0)); + verify(mSystemPropertiesHelper, times(1)) + .getBoolean(fakeStorageKey(FLAG_RESID_0), false); } private void defineFlag(int resId, boolean value) { @@ -162,12 +130,12 @@ public class FeatureFlagReaderTest extends SysuiTestCase { } private void overrideFlag(int resId, boolean value) { - when(mDeviceConfig.getBoolean(eq(fakeStorageKey(resId)), anyBoolean())) + when(mSystemPropertiesHelper.getBoolean(eq(fakeStorageKey(resId)), anyBoolean())) .thenReturn(value); } private String fakeStorageKey(@BoolRes int resId) { - return "flag_testname_" + resId; + return "persist.systemui.flag_testname_" + resId; } private static final int FLAG_RESID_0 = 47; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java index e855834dcad4..1ec1da44c0b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java @@ -33,7 +33,7 @@ import android.widget.TextView; import androidx.test.filters.SmallTest; -import com.android.keyguard.CarrierTextManager; +import com.android.keyguard.CarrierTextController; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.utils.leaks.LeakCheckedTest; @@ -54,7 +54,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { private QSCarrierGroupController mQSCarrierGroupController; private NetworkController.SignalCallback mSignalCallback; - private CarrierTextManager.CarrierTextCallback mCallback; + private CarrierTextController.CarrierTextCallback mCallback; @Mock private QSCarrierGroup mQSCarrierGroup; @Mock @@ -62,9 +62,9 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { @Mock private NetworkController mNetworkController; @Mock - private CarrierTextManager.Builder mCarrierTextControllerBuilder; + private CarrierTextController.Builder mCarrierTextControllerBuilder; @Mock - private CarrierTextManager mCarrierTextManager; + private CarrierTextController mCarrierTextController; private TestableLooper mTestableLooper; @Before @@ -83,11 +83,11 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { .thenReturn(mCarrierTextControllerBuilder); when(mCarrierTextControllerBuilder.setShowMissingSim(anyBoolean())) .thenReturn(mCarrierTextControllerBuilder); - when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextManager); + when(mCarrierTextControllerBuilder.build()).thenReturn(mCarrierTextController); doAnswer(invocation -> mCallback = invocation.getArgument(0)) - .when(mCarrierTextManager) - .setListening(any(CarrierTextManager.CarrierTextCallback.class)); + .when(mCarrierTextController) + .setListening(any(CarrierTextController.CarrierTextCallback.class)); when(mQSCarrierGroup.getNoSimTextView()).thenReturn(new TextView(mContext)); when(mQSCarrierGroup.getCarrier1View()).thenReturn(mock(QSCarrier.class)); @@ -113,8 +113,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 1, subscriptionIds length 1, anySims false - CarrierTextManager.CarrierTextCallbackInfo - c1 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c1 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{""}, false, @@ -122,8 +122,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c1); // listOfCarriers length 1, subscriptionIds length 1, anySims true - CarrierTextManager.CarrierTextCallbackInfo - c2 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c2 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, @@ -131,8 +131,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c2); // listOfCarriers length 2, subscriptionIds length 2, anySims false - CarrierTextManager.CarrierTextCallbackInfo - c3 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c3 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, false, @@ -140,8 +140,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c3); // listOfCarriers length 2, subscriptionIds length 2, anySims true - CarrierTextManager.CarrierTextCallbackInfo - c4 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c4 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -159,8 +159,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { (Answer<Integer>) invocationOnMock -> invocationOnMock.getArgument(0)); // listOfCarriers length 2, subscriptionIds length 1, anySims false - CarrierTextManager.CarrierTextCallbackInfo - c1 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c1 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, false, @@ -168,8 +168,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c1); // listOfCarriers length 2, subscriptionIds length 1, anySims true - CarrierTextManager.CarrierTextCallbackInfo - c2 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c2 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -177,8 +177,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c2); // listOfCarriers length 1, subscriptionIds length 2, anySims false - CarrierTextManager.CarrierTextCallbackInfo - c3 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c3 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{""}, false, @@ -186,8 +186,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { mCallback.updateCarrierInfo(c3); // listOfCarriers length 1, subscriptionIds length 2, anySims true - CarrierTextManager.CarrierTextCallbackInfo - c4 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c4 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, @@ -203,8 +203,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { when(spiedCarrierGroupController.getSlotIndex(anyInt())).thenReturn( SubscriptionManager.INVALID_SIM_SLOT_INDEX); - CarrierTextManager.CarrierTextCallbackInfo - c4 = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + c4 = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{"", ""}, true, @@ -223,8 +223,8 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest { @Test public void testNoEmptyVisibleView_airplaneMode() { - CarrierTextManager.CarrierTextCallbackInfo - info = new CarrierTextManager.CarrierTextCallbackInfo( + CarrierTextController.CarrierTextCallbackInfo + info = new CarrierTextController.CarrierTextCallbackInfo( "", new CharSequence[]{""}, true, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index d69d2dbdd841..e788a1c0954b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -61,7 +61,6 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardStatusViewController; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; -import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.dagger.KeyguardStatusViewComponent; import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.R; @@ -207,16 +206,10 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private KeyguardStatusViewComponent mKeyguardStatusViewComponent; @Mock - private KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory; - @Mock - private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent; - @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; @Mock private KeyguardStatusViewController mKeyguardStatusViewController; @Mock - private KeyguardStatusBarViewController mKeyguardStatusBarViewController; - @Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; @Mock private AuthController mAuthController; @@ -304,10 +297,6 @@ public class NotificationPanelViewTest extends SysuiTestCase { new ViewGroup.LayoutParams(600, 400)); when(mNotificationStackScrollLayoutController.getLayoutParams()).thenReturn( new ViewGroup.LayoutParams(600, 400)); - when(mKeyguardStatusBarViewComponentFactory.build(any())) - .thenReturn(mKeyguardStatusBarViewComponent); - when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController()) - .thenReturn(mKeyguardStatusBarViewController); mNotificationPanelViewController = new NotificationPanelViewController(mView, mResources, @@ -326,7 +315,6 @@ public class NotificationPanelViewTest extends SysuiTestCase { mKeyguardStatusViewComponentFactory, mKeyguardQsUserSwitchComponentFactory, mKeyguardUserSwitcherComponentFactory, - mKeyguardStatusBarViewComponentFactory, mQSDetailDisplayer, mGroupManager, mNotificationAreaController, diff --git a/packages/SystemUI/tools/lint/baseline.xml b/packages/SystemUI/tools/lint/baseline.xml index 3e494032b8e2..9a2e3207a6f4 100644 --- a/packages/SystemUI/tools/lint/baseline.xml +++ b/packages/SystemUI/tools/lint/baseline.xml @@ -1262,17 +1262,6 @@ <issue id="MergeRootFrame" message="This `<FrameLayout>` can be replaced with a `<merge>` tag" - errorLine1="<FrameLayout" - errorLine2="^"> - <location - file="res/layout/pip_menu_activity.xml" - line="16" - column="1"/> - </issue> - - <issue - id="MergeRootFrame" - message="This `<FrameLayout>` can be replaced with a `<merge>` tag" errorLine1="<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"" errorLine2="^"> <location diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index 22efd3718d7a..eb30fdeddd90 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -118,6 +118,9 @@ class AccessibilityUserState { private int mNonInteractiveUiTimeout = 0; private int mInteractiveUiTimeout = 0; private int mLastSentClientState = -1; + + /** {@code true} if the device config supports magnification area. */ + private final boolean mSupportMagnificationArea; // The magnification mode of default display. private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; // The magnification capabilities used to know magnification mode could be switched. @@ -138,6 +141,10 @@ class AccessibilityUserState { private int mSoftKeyboardShowMode = SHOW_MODE_AUTO; boolean isValidMagnificationModeLocked() { + if (!mSupportMagnificationArea + && mMagnificationMode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { + return false; + } return (mMagnificationCapabilities & mMagnificationMode) != 0; } @@ -156,6 +163,8 @@ class AccessibilityUserState { R.color.accessibility_focus_highlight_color); mFocusStrokeWidth = mFocusStrokeWidthDefaultValue; mFocusColor = mFocusColorDefaultValue; + mSupportMagnificationArea = mContext.getResources().getBoolean( + R.bool.config_magnification_area); } boolean isHandlingAccessibilityEventsLocked() { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 0ce26739b51c..5cb9d8ff3f31 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -70,6 +70,7 @@ import android.content.pm.IDataLoaderStatusListener; import android.content.pm.IPackageInstallObserver2; import android.content.pm.IPackageInstallerSession; import android.content.pm.IPackageInstallerSessionFileSystemConnector; +import android.content.pm.IPackageLoadingProgressCallback; import android.content.pm.InstallationFile; import android.content.pm.InstallationFileParcel; import android.content.pm.PackageInfo; @@ -321,6 +322,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private float mProgress = 0; @GuardedBy("mLock") private float mReportedProgress = -1; + @GuardedBy("mLock") + private float mIncrementalProgress = 0; /** State of the session. */ @GuardedBy("mLock") @@ -3770,7 +3773,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir, inheritedDir, params, statusListener, healthCheckParams, healthListener, - addedFiles, perUidReadTimeouts); + addedFiles, perUidReadTimeouts, + new IPackageLoadingProgressCallback.Stub() { + @Override + public void onPackageLoadingProgressChanged(float progress) { + synchronized (mLock) { + mIncrementalProgress = progress; + } + } + }); return false; } catch (IOException e) { throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(), diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java index 96248c3711e3..0974537e2584 100644 --- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java +++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java @@ -18,22 +18,65 @@ package com.android.server.speech; import static com.android.internal.infra.AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS; +import android.annotation.Nullable; +import android.app.AppOpsManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; import android.os.RemoteException; import android.speech.IRecognitionListener; import android.speech.IRecognitionService; import android.speech.RecognitionService; +import android.speech.SpeechRecognizer; +import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.ServiceConnector; final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecognitionService> { private static final String TAG = RemoteSpeechRecognitionService.class.getSimpleName(); - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; - RemoteSpeechRecognitionService(Context context, ComponentName serviceName, int userId) { + private static final String APP_OP_MESSAGE = "Recording audio for speech recognition"; + private static final String RECORD_AUDIO_APP_OP = + AppOpsManager.permissionToOp(android.Manifest.permission.RECORD_AUDIO); + + private final Object mLock = new Object(); + + private boolean mConnected = false; + + @Nullable + private IRecognitionListener mListener; + + @Nullable + @GuardedBy("mLock") + private String mPackageName; + + @Nullable + @GuardedBy("mLock") + private String mFeatureId; + + @Nullable + @GuardedBy("mLock") + private DelegatingListener mDelegatingListener; + + // Makes sure we can block startListening() if session is still in progress. + @GuardedBy("mLock") + private boolean mSessionInProgress = false; + + // Makes sure we call startProxyOp / finishProxyOp at right times and only once per session. + @GuardedBy("mLock") + private boolean mRecordingInProgress = false; + + private final int mCallingUid; + private final AppOpsManager mAppOpsManager; + private final ComponentName mComponentName; + + RemoteSpeechRecognitionService( + Context context, ComponentName serviceName, int userId, int callingUid) { super(context, new Intent(RecognitionService.SERVICE_INTERFACE).setComponent(serviceName), Context.BIND_AUTO_CREATE @@ -43,46 +86,197 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn userId, IRecognitionService.Stub::asInterface); + mCallingUid = callingUid; + mAppOpsManager = mContext.getSystemService(AppOpsManager.class); + mComponentName = serviceName; + if (DEBUG) { Slog.i(TAG, "Bound to recognition service at: " + serviceName.flattenToString()); } } + ComponentName getServiceComponentName() { + return mComponentName; + } + void startListening(Intent recognizerIntent, IRecognitionListener listener, String packageName, - String featureId) throws RemoteException { + String featureId) { if (DEBUG) { - Slog.i(TAG, "#startListening for package: " + packageName + ", feature=" + featureId); + Slog.i(TAG, String.format("#startListening for package: %s, feature=%s, callingUid=%d", + packageName, featureId, mCallingUid)); + } + + if (listener == null) { + Log.w(TAG, "#startListening called with no preceding #setListening - ignoring"); + return; + } + + if (!mConnected) { + tryRespondWithError(listener, SpeechRecognizer.ERROR_SERVER_DISCONNECTED); + return; + } + + synchronized (mLock) { + if (mSessionInProgress) { + Slog.i(TAG, "#startListening called while listening is in progress."); + tryRespondWithError(listener, SpeechRecognizer.ERROR_RECOGNIZER_BUSY); + return; + } + + if (startProxyOp(packageName, featureId) != AppOpsManager.MODE_ALLOWED) { + tryRespondWithError(listener, SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS); + return; + } + mSessionInProgress = true; + mRecordingInProgress = true; + + mListener = listener; + mDelegatingListener = new DelegatingListener(listener, () -> { + // To be invoked in terminal calls of the callback: results() or error() + if (DEBUG) { + Slog.i(TAG, "Recognition session complete"); + } + + synchronized (mLock) { + resetStateLocked(); + } + }); + mPackageName = packageName; + mFeatureId = featureId; + + run(service -> + service.startListening( + recognizerIntent, + mDelegatingListener, + packageName, + featureId, + mCallingUid)); } - run(service -> service.startListening(recognizerIntent, listener, packageName, featureId)); } - void stopListening(IRecognitionListener listener, String packageName, String featureId) - throws RemoteException { + void stopListening( + IRecognitionListener listener, String packageName, String featureId) { if (DEBUG) { Slog.i(TAG, "#stopListening for package: " + packageName + ", feature=" + featureId); } - run(service -> service.stopListening(listener, packageName, featureId)); + + if (!mConnected) { + tryRespondWithError(listener, SpeechRecognizer.ERROR_SERVER_DISCONNECTED); + return; + } + + synchronized (mLock) { + if (mListener == null) { + Log.w(TAG, "#stopListening called with no preceding #startListening - ignoring"); + tryRespondWithError(listener, SpeechRecognizer.ERROR_CLIENT); + return; + } + + if (mListener.asBinder() != listener.asBinder()) { + Log.w(TAG, "#stopListening called with an unexpected listener"); + tryRespondWithError(listener, SpeechRecognizer.ERROR_CLIENT); + return; + } + + if (!mRecordingInProgress) { + Slog.i(TAG, "#stopListening called while listening isn't in progress, ignoring."); + return; + } + mRecordingInProgress = false; + + finishProxyOp(packageName, featureId); + + run(service -> service.stopListening(mDelegatingListener, packageName, featureId)); + } } - void cancel(IRecognitionListener listener, String packageName, String featureId) - throws RemoteException { + void cancel( + IRecognitionListener listener, + String packageName, + String featureId, + boolean isShutdown) { if (DEBUG) { Slog.i(TAG, "#cancel for package: " + packageName + ", feature=" + featureId); } - run(service -> service.cancel(listener, packageName, featureId)); + + if (!mConnected) { + tryRespondWithError(listener, SpeechRecognizer.ERROR_SERVER_DISCONNECTED); + } + + synchronized (mLock) { + if (mListener == null) { + if (DEBUG) { + Log.w(TAG, "#cancel called with no preceding #startListening - ignoring"); + } + return; + } + + if (mListener.asBinder() != listener.asBinder()) { + Log.w(TAG, "#cancel called with an unexpected listener"); + tryRespondWithError(listener, SpeechRecognizer.ERROR_CLIENT); + return; + } + + // Temporary reference to allow for resetting the hard link mDelegatingListener to null. + IRecognitionListener delegatingListener = mDelegatingListener; + + run(service -> service.cancel(delegatingListener, packageName, featureId, isShutdown)); + + if (mRecordingInProgress) { + finishProxyOp(packageName, featureId); + } + mRecordingInProgress = false; + mSessionInProgress = false; + + mDelegatingListener = null; + mListener = null; + + // Schedule to unbind after cancel is delivered. + if (isShutdown) { + run(service -> unbind()); + } + } + } + + void shutdown() { + synchronized (mLock) { + if (this.mListener == null) { + if (DEBUG) { + Slog.i(TAG, "Package died, but session wasn't initialized. " + + "Not invoking #cancel"); + } + return; + } + } + + cancel(mListener, mPackageName, mFeatureId, true /* isShutdown */); } @Override // from ServiceConnector.Impl protected void onServiceConnectionStatusChanged( IRecognitionService service, boolean connected) { - if (!DEBUG) { - return; + mConnected = connected; + + if (DEBUG) { + if (connected) { + Slog.i(TAG, "Connected to speech recognition service"); + } else { + Slog.w(TAG, "Disconnected from speech recognition service"); + } } - if (connected) { - Slog.i(TAG, "Connected to ASR service"); - } else { - Slog.w(TAG, "Disconnected from ASR service"); + synchronized (mLock) { + if (!connected) { + if (mListener == null) { + Slog.i(TAG, "Connection to speech recognition service lost, but no " + + "#startListening has been invoked yet."); + return; + } + + tryRespondWithError(mListener, SpeechRecognizer.ERROR_SERVER_DISCONNECTED); + + resetStateLocked(); + } } } @@ -90,4 +284,119 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn protected long getAutoDisconnectTimeoutMs() { return PERMANENT_BOUND_TIMEOUT_MS; } + + private void resetStateLocked() { + if (mRecordingInProgress && mPackageName != null && mFeatureId != null) { + finishProxyOp(mPackageName, mFeatureId); + } + + mListener = null; + mDelegatingListener = null; + mSessionInProgress = false; + mRecordingInProgress = false; + } + + private int startProxyOp(String packageName, String featureId) { + final long identity = Binder.clearCallingIdentity(); + try { + return mAppOpsManager.startProxyOp( + RECORD_AUDIO_APP_OP, + mCallingUid, + packageName, + featureId, + APP_OP_MESSAGE); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + private void finishProxyOp(String packageName, String featureId) { + final long identity = Binder.clearCallingIdentity(); + try { + mAppOpsManager.finishProxyOp( + RECORD_AUDIO_APP_OP, mCallingUid, packageName, featureId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + private static void tryRespondWithError(IRecognitionListener listener, int errorCode) { + if (DEBUG) { + Slog.i(TAG, "Responding with error " + errorCode); + } + + try { + if (listener != null) { + listener.onError(errorCode); + } + } catch (RemoteException e) { + Slog.w(TAG, + String.format("Failed to respond with an error %d to the client", errorCode), + e); + } + } + + private static class DelegatingListener extends IRecognitionListener.Stub { + + private final IRecognitionListener mRemoteListener; + private final Runnable mOnSessionComplete; + + DelegatingListener(IRecognitionListener listener, Runnable onSessionComplete) { + mRemoteListener = listener; + mOnSessionComplete = onSessionComplete; + } + + @Override + public void onReadyForSpeech(Bundle params) throws RemoteException { + mRemoteListener.onReadyForSpeech(params); + } + + @Override + public void onBeginningOfSpeech() throws RemoteException { + mRemoteListener.onBeginningOfSpeech(); + } + + @Override + public void onRmsChanged(float rmsdB) throws RemoteException { + mRemoteListener.onRmsChanged(rmsdB); + } + + @Override + public void onBufferReceived(byte[] buffer) throws RemoteException { + mRemoteListener.onBufferReceived(buffer); + } + + @Override + public void onEndOfSpeech() throws RemoteException { + mRemoteListener.onEndOfSpeech(); + } + + @Override + public void onError(int error) throws RemoteException { + if (DEBUG) { + Slog.i(TAG, String.format("Error %d during recognition session", error)); + } + mOnSessionComplete.run(); + mRemoteListener.onError(error); + } + + @Override + public void onResults(Bundle results) throws RemoteException { + if (DEBUG) { + Slog.i(TAG, "#onResults invoked for a recognition session"); + } + mOnSessionComplete.run(); + mRemoteListener.onResults(results); + } + + @Override + public void onPartialResults(Bundle results) throws RemoteException { + mRemoteListener.onPartialResults(results); + } + + @Override + public void onEvent(int eventType, Bundle params) throws RemoteException { + mRemoteListener.onEvent(eventType, params); + } + } } diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java index 592ba9e616b8..dbe73546d748 100644 --- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java +++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerService.java @@ -18,7 +18,9 @@ package com.android.server.speech; import android.annotation.NonNull; import android.annotation.UserIdInt; +import android.content.ComponentName; import android.content.Context; +import android.os.IBinder; import android.os.UserHandle; import android.speech.IRecognitionServiceManager; import android.speech.IRecognitionServiceManagerCallback; @@ -42,6 +44,7 @@ public final class SpeechRecognitionManagerService extends public SpeechRecognitionManagerService(@NonNull Context context) { super(context, + // TODO(b/176578753): think if we want to favor the particular service here. new FrameworkResourcesServiceNameResolver( context, R.string.config_defaultOnDeviceSpeechRecognitionService), @@ -63,11 +66,15 @@ public final class SpeechRecognitionManagerService extends final class SpeechRecognitionManagerServiceStub extends IRecognitionServiceManager.Stub { @Override - public void createSession(IRecognitionServiceManagerCallback callback) { + public void createSession( + ComponentName componentName, + IBinder clientToken, + boolean onDevice, + IRecognitionServiceManagerCallback callback) { int userId = UserHandle.getCallingUserId(); synchronized (mLock) { SpeechRecognitionManagerServiceImpl service = getServiceForUserLocked(userId); - service.createSessionLocked(callback); + service.createSessionLocked(componentName, clientToken, onDevice, callback); } } } diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java index bcaf174b1d92..2656a3d32555 100644 --- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java +++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java @@ -24,30 +24,44 @@ import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.os.Binder; +import android.os.IBinder; import android.os.RemoteException; import android.speech.IRecognitionListener; import android.speech.IRecognitionService; import android.speech.IRecognitionServiceManagerCallback; +import android.speech.SpeechRecognizer; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.infra.AbstractPerUserSystemService; +import com.google.android.collect.Sets; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + final class SpeechRecognitionManagerServiceImpl extends AbstractPerUserSystemService<SpeechRecognitionManagerServiceImpl, SpeechRecognitionManagerService> { - private static final String TAG = SpeechRecognitionManagerServiceImpl.class.getSimpleName(); + private static final int MAX_CONCURRENT_CONNECTIONS_BY_CLIENT = 10; + + private final Object mLock = new Object(); + + @NonNull @GuardedBy("mLock") - @Nullable - private RemoteSpeechRecognitionService mRemoteService; + private final Map<Integer, Set<RemoteSpeechRecognitionService>> mRemoteServicesByUid = + new HashMap<>(); SpeechRecognitionManagerServiceImpl( @NonNull SpeechRecognitionManagerService master, @NonNull Object lock, @UserIdInt int userId, boolean disabled) { super(master, lock, userId); - updateRemoteServiceLocked(); } @GuardedBy("mLock") @@ -67,92 +81,196 @@ final class SpeechRecognitionManagerServiceImpl extends @Override // from PerUserSystemService protected boolean updateLocked(boolean disabled) { final boolean enabledChanged = super.updateLocked(disabled); - updateRemoteServiceLocked(); return enabledChanged; } - /** - * Updates the reference to the remote service. - */ - @GuardedBy("mLock") - private void updateRemoteServiceLocked() { - if (mRemoteService != null) { - if (mMaster.debug) { - Slog.d(TAG, "updateRemoteService(): destroying old remote service"); - } - mRemoteService.unbind(); - mRemoteService = null; + void createSessionLocked( + ComponentName componentName, + IBinder clientToken, + boolean onDevice, + IRecognitionServiceManagerCallback callback) { + if (mMaster.debug) { + Slog.i(TAG, String.format("#createSessionLocked, component=%s, onDevice=%s", + componentName, onDevice)); + } + + ComponentName serviceComponent = componentName; + if (onDevice) { + serviceComponent = getOnDeviceComponentNameLocked(); } - } - void createSessionLocked(IRecognitionServiceManagerCallback callback) { - // TODO(b/176578753): check clients have record audio permission. - // TODO(b/176578753): verify caller package is the one supplied + if (serviceComponent == null) { + tryRespondWithError(callback, SpeechRecognizer.ERROR_CLIENT); + return; + } - RemoteSpeechRecognitionService service = ensureRemoteServiceLocked(); + final int creatorCallingUid = Binder.getCallingUid(); + Set<String> creatorPackageNames = + Sets.newArraySet( + getContext().getPackageManager().getPackagesForUid(creatorCallingUid)); + + RemoteSpeechRecognitionService service = createService(creatorCallingUid, serviceComponent); if (service == null) { - tryRespondWithError(callback); + tryRespondWithError(callback, SpeechRecognizer.ERROR_TOO_MANY_REQUESTS); return; } + IBinder.DeathRecipient deathRecipient = + () -> handleClientDeath(creatorCallingUid, service, true /* invoke #cancel */); + + try { + clientToken.linkToDeath(deathRecipient, 0); + } catch (RemoteException e) { + // RemoteException == binder already died, schedule disconnect anyway. + handleClientDeath(creatorCallingUid, service, true /* invoke #cancel */); + } + service.connect().thenAccept(binderService -> { if (binderService != null) { try { callback.onSuccess(new IRecognitionService.Stub() { @Override - public void startListening(Intent recognizerIntent, + public void startListening( + Intent recognizerIntent, IRecognitionListener listener, - String packageName, String featureId) throws RemoteException { + String packageName, + String featureId, + int callingUid) throws RemoteException { + verifyCallerIdentity( + creatorCallingUid, packageName, creatorPackageNames, listener); + if (callingUid != creatorCallingUid) { + listener.onError(SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS); + return; + } + service.startListening( recognizerIntent, listener, packageName, featureId); } @Override - public void stopListening(IRecognitionListener listener, + public void stopListening( + IRecognitionListener listener, String packageName, String featureId) throws RemoteException { + verifyCallerIdentity( + creatorCallingUid, packageName, creatorPackageNames, listener); + service.stopListening(listener, packageName, featureId); } @Override - public void cancel(IRecognitionListener listener, + public void cancel( + IRecognitionListener listener, String packageName, - String featureId) throws RemoteException { - service.cancel(listener, packageName, featureId); + String featureId, + boolean isShutdown) throws RemoteException { + verifyCallerIdentity( + creatorCallingUid, packageName, creatorPackageNames, listener); + + service.cancel(listener, packageName, featureId, isShutdown); + + if (isShutdown) { + handleClientDeath( + creatorCallingUid, + service, + false /* invoke #cancel */); + clientToken.unlinkToDeath(deathRecipient, 0); + } } }); } catch (RemoteException e) { Slog.e(TAG, "Error creating a speech recognition session", e); - tryRespondWithError(callback); + tryRespondWithError(callback, SpeechRecognizer.ERROR_CLIENT); } } else { - tryRespondWithError(callback); + tryRespondWithError(callback, SpeechRecognizer.ERROR_CLIENT); } }); } + private void verifyCallerIdentity( + int creatorCallingUid, + String packageName, + Set<String> creatorPackageNames, + IRecognitionListener listener) throws RemoteException { + if (creatorCallingUid != Binder.getCallingUid() + || !creatorPackageNames.contains(packageName)) { + listener.onError(SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS); + } + } + + private void handleClientDeath( + int callingUid, + RemoteSpeechRecognitionService service, boolean invokeCancel) { + if (invokeCancel) { + service.shutdown(); + } + removeService(callingUid, service); + } + @GuardedBy("mLock") @Nullable - private RemoteSpeechRecognitionService ensureRemoteServiceLocked() { - if (mRemoteService == null) { - final String serviceName = getComponentNameLocked(); - if (serviceName == null) { - if (mMaster.verbose) { - Slog.v(TAG, "ensureRemoteServiceLocked(): no service component name."); - } + private ComponentName getOnDeviceComponentNameLocked() { + final String serviceName = getComponentNameLocked(); + if (serviceName == null) { + if (mMaster.verbose) { + Slog.v(TAG, "ensureRemoteServiceLocked(): no service component name."); + } + return null; + } + return ComponentName.unflattenFromString(serviceName); + } + + private RemoteSpeechRecognitionService createService( + int callingUid, ComponentName serviceComponent) { + synchronized (mLock) { + Set<RemoteSpeechRecognitionService> servicesForClient = + mRemoteServicesByUid.get(callingUid); + + if (servicesForClient != null + && servicesForClient.size() >= MAX_CONCURRENT_CONNECTIONS_BY_CLIENT) { return null; } - final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName); - mRemoteService = - new RemoteSpeechRecognitionService(getContext(), serviceComponent, mUserId); + + if (servicesForClient != null) { + Optional<RemoteSpeechRecognitionService> existingService = + servicesForClient + .stream() + .filter(service -> + service.getServiceComponentName().equals(serviceComponent)) + .findFirst(); + if (existingService.isPresent()) { + return existingService.get(); + } + } + + RemoteSpeechRecognitionService service = + new RemoteSpeechRecognitionService( + getContext(), serviceComponent, getUserId(), callingUid); + + Set<RemoteSpeechRecognitionService> valuesByCaller = + mRemoteServicesByUid.computeIfAbsent(callingUid, key -> new HashSet<>()); + valuesByCaller.add(service); + + return service; + } + } + + private void removeService(int callingUid, RemoteSpeechRecognitionService service) { + synchronized (mLock) { + Set<RemoteSpeechRecognitionService> valuesByCaller = + mRemoteServicesByUid.get(callingUid); + if (valuesByCaller != null) { + valuesByCaller.remove(service); + } } - return mRemoteService; } - private static void tryRespondWithError(IRecognitionServiceManagerCallback callback) { + private static void tryRespondWithError(IRecognitionServiceManagerCallback callback, + int errorCode) { try { - callback.onError(); + callback.onError(errorCode); } catch (RemoteException e) { Slog.w(TAG, "Failed to respond with error"); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 589a8c31a07b..75a7660c0ac1 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -864,7 +864,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mTaskChangeNotificationController = new TaskChangeNotificationController(mGlobalLock, mTaskSupervisor, mH); - mLockTaskController = new LockTaskController(mContext, mTaskSupervisor, mH); + mLockTaskController = new LockTaskController(mContext, mTaskSupervisor, mH, + mTaskChangeNotificationController); mActivityStartController = new ActivityStartController(this); setRecentTasks(new RecentTasks(this, mTaskSupervisor)); mVrController = new VrController(mGlobalLock); diff --git a/services/core/java/com/android/server/wm/ScreenshotHashController.java b/services/core/java/com/android/server/wm/DisplayHashController.java index 03f4e2891d19..7e16c22ee15e 100644 --- a/services/core/java/com/android/server/wm/ScreenshotHashController.java +++ b/services/core/java/com/android/server/wm/DisplayHashController.java @@ -16,9 +16,8 @@ package com.android.server.wm; -import static android.service.screenshot.ScreenshotHasherService.EXTRA_SCREENSHOT_HASH; -import static android.service.screenshot.ScreenshotHasherService.EXTRA_VERIFICATION_STATUS; -import static android.service.screenshot.ScreenshotHasherService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS; +import static android.service.displayhash.DisplayHasherService.EXTRA_VERIFIED_DISPLAY_HASH; +import static android.service.displayhash.DisplayHasherService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -46,11 +45,12 @@ import android.os.Message; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; -import android.service.screenshot.IScreenshotHasherService; -import android.service.screenshot.ScreenshotHash; -import android.service.screenshot.ScreenshotHasherService; +import android.service.displayhash.DisplayHasherService; +import android.service.displayhash.IDisplayHasherService; import android.util.Slog; import android.view.MagnificationSpec; +import android.view.displayhash.DisplayHash; +import android.view.displayhash.VerifiedDisplayHash; import com.android.internal.annotations.GuardedBy; @@ -61,29 +61,29 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; /** - * Handles requests into {@link android.service.screenshot.ScreenshotHasherService} + * Handles requests into {@link android.service.displayhash.DisplayHasherService} * * Do not hold the {@link WindowManagerService#mGlobalLock} when calling methods since they are * blocking calls into another service. */ -public class ScreenshotHashController { - private static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenshotHashController" : TAG_WM; +public class DisplayHashController { + private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayHashController" : TAG_WM; private static final boolean DEBUG = false; private final Object mServiceConnectionLock = new Object(); @GuardedBy("mServiceConnectionLock") - private ScreenshotHasherServiceConnection mServiceConnection; + private DisplayHasherServiceConnection mServiceConnection; private final Context mContext; /** - * Lock used for the cached {@link #mHashingAlgorithms} array + * Lock used for the cached {@link #mHashAlgorithms} array */ - private final Object mHashingAlgorithmsLock = new Object(); + private final Object mHashAlgorithmsLock = new Object(); @GuardedBy("mHashingAlgorithmsLock") - private String[] mHashingAlgorithms; + private String[] mHashAlgorithms; private final Handler mHandler; @@ -94,24 +94,24 @@ public class ScreenshotHashController { private final RectF mTmpRectF = new RectF(); private interface Command { - void run(IScreenshotHasherService service) throws RemoteException; + void run(IDisplayHasherService service) throws RemoteException; } - ScreenshotHashController(Context context) { + DisplayHashController(Context context) { mContext = context; mHandler = new Handler(Looper.getMainLooper()); mSalt = UUID.randomUUID().toString().getBytes(); } - String[] getSupportedHashingAlgorithms() { + String[] getSupportedHashAlgorithms() { // We have a separate lock for the hashing algorithm array since it doesn't need to make // the request through the service connection. Instead, we have a lock to ensure we can // properly cache the hashing algorithms array so we don't need to call into the // ExtServices process for each request. - synchronized (mHashingAlgorithmsLock) { + synchronized (mHashAlgorithmsLock) { // Already have cached values - if (mHashingAlgorithms != null) { - return mHashingAlgorithms; + if (mHashAlgorithms != null) { + return mHashAlgorithms; } final ServiceInfo serviceInfo = getServiceInfo(); @@ -128,55 +128,48 @@ public class ScreenshotHashController { final int resourceId = serviceInfo.metaData.getInt( SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS); - mHashingAlgorithms = res.getStringArray(resourceId); + mHashAlgorithms = res.getStringArray(resourceId); - return mHashingAlgorithms; + return mHashAlgorithms; } } - boolean verifyScreenshotHash(ScreenshotHash screenshotHash) { + @Nullable + VerifiedDisplayHash verifyDisplayHash(DisplayHash displayHash) { final SyncCommand syncCommand = new SyncCommand(); Bundle results = syncCommand.run((service, remoteCallback) -> { try { - service.verifyScreenshotHash(mSalt, screenshotHash, remoteCallback); + service.verifyDisplayHash(mSalt, displayHash, remoteCallback); } catch (RemoteException e) { - Slog.e(TAG, "Failed to invoke verifyScreenshotHash command"); + Slog.e(TAG, "Failed to invoke verifyDisplayHash command"); } }); - return results.getBoolean(EXTRA_VERIFICATION_STATUS); + return results.getParcelable(EXTRA_VERIFIED_DISPLAY_HASH); } - ScreenshotHash generateScreenshotHash(HardwareBuffer screenshot, Rect bounds, - String hashAlgorithm) { - final SyncCommand syncCommand = new SyncCommand(); - Bundle results = syncCommand.run((service, remoteCallback) -> { - try { - service.generateScreenshotHash(mSalt, screenshot, bounds, hashAlgorithm, - remoteCallback); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to invoke generateScreenshotHash command", e); - } - }); - - return results.getParcelable(EXTRA_SCREENSHOT_HASH); + void generateDisplayHash(HardwareBuffer buffer, Rect bounds, + String hashAlgorithm, RemoteCallback callback) { + connectAndRun( + service -> service.generateDisplayHash(mSalt, buffer, bounds, hashAlgorithm, + callback)); } /** - * Calculate the bounds to take the screenshot when generating the ScreenshotHash. This - * takes into account window transform, magnification, and display bounds. + * Calculate the bounds to generate the hash for. This takes into account window transform, + * magnification, and display bounds. * * Call while holding {@link WindowManagerService#mGlobalLock} * - * @param win Window that the ScreenshotHash is generated for. - * @param boundsInWindow The bounds passed in about where in the window to take the screenshot. - * @param outBounds The result of the calculated bounds + * @param win Window that the DisplayHash is generated for. + * @param boundsInWindow The bounds in the window where to generate the hash. + * @param outBounds The result of the calculated bounds */ - void calculateScreenshotHashBoundsLocked(WindowState win, Rect boundsInWindow, + void calculateDisplayHashBoundsLocked(WindowState win, Rect boundsInWindow, Rect outBounds) { if (DEBUG) { Slog.d(TAG, - "calculateScreenshotHashBoundsLocked: boundsInWindow=" + boundsInWindow); + "calculateDisplayHashBoundsLocked: boundsInWindow=" + boundsInWindow); } outBounds.set(boundsInWindow); @@ -195,7 +188,7 @@ public class ScreenshotHashController { if (DEBUG) { Slog.d(TAG, - "calculateScreenshotHashBoundsLocked: boundsIntersectWindow=" + outBounds); + "calculateDisplayHashBoundsLocked: boundsIntersectWindow=" + outBounds); } if (outBounds.isEmpty()) { @@ -210,7 +203,7 @@ public class ScreenshotHashController { outBounds.set((int) mTmpRectF.left, (int) mTmpRectF.top, (int) mTmpRectF.right, (int) mTmpRectF.bottom); if (DEBUG) { - Slog.d(TAG, "calculateScreenshotHashBoundsLocked: boundsInDisplay=" + outBounds); + Slog.d(TAG, "calculateDisplayHashBoundsLocked: boundsInDisplay=" + outBounds); } // Apply the magnification spec values to the bounds since the content could be magnified @@ -221,7 +214,7 @@ public class ScreenshotHashController { } if (DEBUG) { - Slog.d(TAG, "calculateScreenshotHashBoundsLocked: boundsWithMagnification=" + Slog.d(TAG, "calculateDisplayHashBoundsLocked: boundsWithMagnification=" + outBounds); } @@ -229,12 +222,12 @@ public class ScreenshotHashController { return; } - // Intersect with the display bounds since it shouldn't take a screenshot of content - // outside the display since it's not visible to the user. + // Intersect with the display bounds since content outside the display are not visible to + // the user. final Rect displayBounds = displayContent.getBounds(); outBounds.intersectUnchecked(displayBounds); if (DEBUG) { - Slog.d(TAG, "calculateScreenshotHashBoundsLocked: finalBounds=" + outBounds); + Slog.d(TAG, "calculateDisplayHashBoundsLocked: finalBounds=" + outBounds); } } @@ -248,7 +241,7 @@ public class ScreenshotHashController { if (DEBUG) Slog.v(TAG, "creating connection"); // Create the connection - mServiceConnection = new ScreenshotHasherServiceConnection(); + mServiceConnection = new DisplayHasherServiceConnection(); final ComponentName component = getServiceComponentName(); if (DEBUG) Slog.v(TAG, "binding to: " + component); @@ -279,7 +272,7 @@ public class ScreenshotHashController { return null; } - final Intent intent = new Intent(ScreenshotHasherService.SERVICE_INTERFACE); + final Intent intent = new Intent(DisplayHasherService.SERVICE_INTERFACE); intent.setPackage(packageName); final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); @@ -296,10 +289,10 @@ public class ScreenshotHashController { if (serviceInfo == null) return null; final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name); - if (!Manifest.permission.BIND_SCREENSHOT_HASHER_SERVICE + if (!Manifest.permission.BIND_DISPLAY_HASHER_SERVICE .equals(serviceInfo.permission)) { Slog.w(TAG, name.flattenToShortString() + " requires permission " - + Manifest.permission.BIND_SCREENSHOT_HASHER_SERVICE); + + Manifest.permission.BIND_DISPLAY_HASHER_SERVICE); return null; } @@ -312,7 +305,7 @@ public class ScreenshotHashController { private Bundle mResult; private final CountDownLatch mCountDownLatch = new CountDownLatch(1); - public Bundle run(BiConsumer<IScreenshotHasherService, RemoteCallback> func) { + public Bundle run(BiConsumer<IDisplayHasherService, RemoteCallback> func) { connectAndRun(service -> { RemoteCallback callback = new RemoteCallback(result -> { mResult = result; @@ -331,9 +324,9 @@ public class ScreenshotHashController { } } - private class ScreenshotHasherServiceConnection implements ServiceConnection { + private class DisplayHasherServiceConnection implements ServiceConnection { @GuardedBy("mServiceConnectionLock") - private IScreenshotHasherService mRemoteService; + private IDisplayHasherService mRemoteService; @GuardedBy("mServiceConnectionLock") private ArrayList<Command> mQueuedCommands; @@ -342,7 +335,7 @@ public class ScreenshotHashController { public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) Slog.v(TAG, "onServiceConnected(): " + name); synchronized (mServiceConnectionLock) { - mRemoteService = IScreenshotHasherService.Stub.asInterface(service); + mRemoteService = IDisplayHasherService.Stub.asInterface(service); if (mQueuedCommands != null) { final int size = mQueuedCommands.size(); if (DEBUG) Slog.d(TAG, "running " + size + " queued commands"); diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 4b3a43432fc5..e18516d7bc3a 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -141,6 +141,7 @@ public class LockTaskController { private final IBinder mToken = new LockTaskToken(); private final ActivityTaskSupervisor mSupervisor; private final Context mContext; + private final TaskChangeNotificationController mTaskChangeNotificationController; // The following system services cannot be final, because they do not exist when this class // is instantiated during device boot @@ -204,10 +205,11 @@ public class LockTaskController { private int mPendingDisableFromDismiss = UserHandle.USER_NULL; LockTaskController(Context context, ActivityTaskSupervisor supervisor, - Handler handler) { + Handler handler, TaskChangeNotificationController taskChangeNotificationController) { mContext = context; mSupervisor = supervisor; mHandler = handler; + mTaskChangeNotificationController = taskChangeNotificationController; } /** @@ -532,6 +534,7 @@ public class LockTaskController { // thread, which makes it guarded by ATMS#mGlobalLock as ATMS#getLockTaskModeState. final int oldLockTaskModeState = mLockTaskModeState; mLockTaskModeState = LOCK_TASK_MODE_NONE; + mTaskChangeNotificationController.notifyLockTaskModeChanged(mLockTaskModeState); // When lock task ends, we enable the status bars. try { setStatusBarState(mLockTaskModeState, userId); @@ -661,6 +664,7 @@ public class LockTaskController { } mWindowManager.onLockTaskStateChanged(lockTaskModeState); mLockTaskModeState = lockTaskModeState; + mTaskChangeNotificationController.notifyLockTaskModeChanged(mLockTaskModeState); setStatusBarState(lockTaskModeState, userId); setKeyguardState(lockTaskModeState, userId); if (getDevicePolicyManager() != null) { diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 8b186796db8d..b82a30847c8d 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -54,10 +54,10 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Process; +import android.os.RemoteCallback; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; -import android.service.screenshot.ScreenshotHash; import android.text.TextUtils; import android.util.ArraySet; import android.util.MergedConfiguration; @@ -850,11 +850,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } @Override - public ScreenshotHash generateScreenshotHash(IWindow window, Rect boundsInWindow, - String hashAlgorithm) { + public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, + RemoteCallback callback) { final long origId = Binder.clearCallingIdentity(); try { - return mService.generateScreenshotHash(this, window, boundsInWindow, hashAlgorithm); + mService.generateDisplayHash(this, window, boundsInWindow, hashAlgorithm, callback); } finally { Binder.restoreCallingIdentity(origId); } diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java index 622fe05b6170..9b7257057836 100644 --- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java @@ -59,6 +59,7 @@ class TaskChangeNotificationController { private static final int NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG = 25; private static final int NOTIFY_ACTIVITY_ROTATED_MSG = 26; private static final int NOTIFY_TASK_MOVED_TO_BACK_LISTENERS_MSG = 27; + private static final int NOTIFY_LOCK_TASK_MODE_CHANGED_MSG = 28; // Delay in notifying task stack change listeners (in millis) private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100; @@ -177,6 +178,10 @@ class TaskChangeNotificationController { l.onTaskMovedToBack((RunningTaskInfo) m.obj); }; + private final TaskStackConsumer mNotifyLockTaskModeChanged = (l, m) -> { + l.onLockTaskModeChanged(m.arg1); + }; + @FunctionalInterface public interface TaskStackConsumer { void accept(ITaskStackListener t, Message m) throws RemoteException; @@ -268,6 +273,9 @@ class TaskChangeNotificationController { case NOTIFY_TASK_MOVED_TO_BACK_LISTENERS_MSG: forAllRemoteListeners(mNotifyTaskMovedToBack, msg); break; + case NOTIFY_LOCK_TASK_MODE_CHANGED_MSG: + forAllRemoteListeners(mNotifyLockTaskModeChanged, msg); + break; } if (msg.obj instanceof SomeArgs) { ((SomeArgs) msg.obj).recycle(); @@ -550,4 +558,11 @@ class TaskChangeNotificationController { forAllLocalListeners(mNotifyTaskMovedToBack, msg); msg.sendToTarget(); } + + void notifyLockTaskModeChanged(int lockTaskModeState) { + final Message msg = mHandler.obtainMessage(NOTIFY_LOCK_TASK_MODE_CHANGED_MSG, + lockTaskModeState, 0 /* unused */); + forAllLocalListeners(mNotifyLockTaskModeChanged, msg); + msg.sendToTarget(); + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5dc5ab767b2e..39b749ef54cb 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -83,6 +83,10 @@ import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID; +import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; +import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; +import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; +import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; @@ -187,6 +191,7 @@ import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.PowerSaveState; +import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -199,7 +204,6 @@ import android.os.Trace; import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; -import android.service.screenshot.ScreenshotHash; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; import android.sysprop.SurfaceFlingerProperties; @@ -261,6 +265,8 @@ import android.view.WindowManager.LayoutParams; import android.view.WindowManager.RemoveContentMode; import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicyConstants.PointerEventListener; +import android.view.displayhash.DisplayHash; +import android.view.displayhash.VerifiedDisplayHash; import android.window.ClientWindowFrames; import android.window.TaskSnapshot; @@ -768,7 +774,8 @@ public class WindowManagerService extends IWindowManager.Stub final EmbeddedWindowController mEmbeddedWindowController; final AnrController mAnrController; - private final ScreenshotHashController mScreenshotHashController; + private final DisplayHashController mDisplayHashController; + @VisibleForTesting final WindowContextListenerController mWindowContextListenerController = new WindowContextListenerController(); @@ -1419,7 +1426,7 @@ public class WindowManagerService extends IWindowManager.Stub mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources( mContext.getResources()); - mScreenshotHashController = new ScreenshotHashController(mContext); + mDisplayHashController = new DisplayHashController(mContext); setGlobalShadowSettings(); mAnrController = new AnrController(this); mStartingSurfaceController = new StartingSurfaceController(this); @@ -8599,39 +8606,42 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public String[] getSupportedScreenshotHashingAlgorithms() { - return mScreenshotHashController.getSupportedHashingAlgorithms(); + public String[] getSupportedDisplayHashAlgorithms() { + return mDisplayHashController.getSupportedHashAlgorithms(); } @Override - public boolean verifyScreenshotHash(ScreenshotHash screenshotHash) { - return mScreenshotHashController.verifyScreenshotHash(screenshotHash); + public VerifiedDisplayHash verifyDisplayHash(DisplayHash displayHash) { + return mDisplayHashController.verifyDisplayHash(displayHash); } - ScreenshotHash generateScreenshotHash(Session session, IWindow window, - Rect boundsInWindow, String hashAlgorithm) { + void generateDisplayHash(Session session, IWindow window, Rect boundsInWindow, + String hashAlgorithm, RemoteCallback callback) { final SurfaceControl displaySurfaceControl; final Rect boundsInDisplay = new Rect(boundsInWindow); synchronized (mGlobalLock) { final WindowState win = windowForClientLocked(session, window, false); if (win == null) { - Slog.w(TAG, "Failed to generate ScreenshotHash. Invalid window"); - return null; + Slog.w(TAG, "Failed to generate DisplayHash. Invalid window"); + sendDisplayHashError(callback, DISPLAY_HASH_ERROR_MISSING_WINDOW); + return; } DisplayContent displayContent = win.getDisplayContent(); if (displayContent == null) { - Slog.w(TAG, "Failed to generate ScreenshotHash. Window is not on a display"); - return null; + Slog.w(TAG, "Failed to generate DisplayHash. Window is not on a display"); + sendDisplayHashError(callback, DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); + return; } displaySurfaceControl = displayContent.getSurfaceControl(); - mScreenshotHashController.calculateScreenshotHashBoundsLocked(win, - boundsInWindow, boundsInDisplay); + mDisplayHashController.calculateDisplayHashBoundsLocked(win, boundsInWindow, + boundsInDisplay); if (boundsInDisplay.isEmpty()) { - Slog.w(TAG, "Failed to generate ScreenshotHash. Bounds are not on screen"); - return null; + Slog.w(TAG, "Failed to generate DisplayHash. Bounds are not on screen"); + sendDisplayHashError(callback, DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); + return; } } @@ -8650,11 +8660,18 @@ public class WindowManagerService extends IWindowManager.Stub SurfaceControl.captureLayers(args); if (screenshotHardwareBuffer == null || screenshotHardwareBuffer.getHardwareBuffer() == null) { - Slog.w(TAG, "Failed to generate ScreenshotHash. Failed to take screenshot"); - return null; + Slog.w(TAG, "Failed to generate DisplayHash. Couldn't capture content"); + sendDisplayHashError(callback, DISPLAY_HASH_ERROR_UNKNOWN); + return; } - return mScreenshotHashController.generateScreenshotHash( - screenshotHardwareBuffer.getHardwareBuffer(), boundsInWindow, hashAlgorithm); + mDisplayHashController.generateDisplayHash(screenshotHardwareBuffer.getHardwareBuffer(), + boundsInWindow, hashAlgorithm, callback); + } + + private void sendDisplayHashError(RemoteCallback callback, int errorCode) { + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode); + callback.sendResult(bundle); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 1cf4ce163640..dd599c9cfb60 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -10092,7 +10092,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int userId = user.id; - // TODO(b/177547285): add CTS test if (mInjector.userManagerIsHeadlessSystemUserMode()) { ComponentName admin = mOwners.getDeviceOwnerComponent(); Slog.i(LOG_TAG, "Automatically setting profile owner (" + admin + ") on new user " @@ -12911,8 +12910,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (mOwners.hasProfileOwner(deviceOwnerUserId)) { return CODE_USER_HAS_PROFILE_OWNER; } + + boolean isHeadlessSystemUserMode = mInjector.userManagerIsHeadlessSystemUserMode(); // System user is always running in headless system user mode. - if (!mInjector.userManagerIsHeadlessSystemUserMode() + if (!isHeadlessSystemUserMode && !mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) { return CODE_USER_NOT_RUNNING; } @@ -12920,7 +12921,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return CODE_HAS_PAIRED; } - if (mInjector.userManagerIsHeadlessSystemUserMode()) { + if (isHeadlessSystemUserMode) { if (deviceOwnerUserId != UserHandle.USER_SYSTEM) { Slog.e(LOG_TAG, "In headless system user mode, " + "device owner can only be set on headless system user."); @@ -12932,9 +12933,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // If shell command runs after user setup completed check device status. Otherwise, OK. if (mIsWatch || hasUserSetupCompleted(UserHandle.USER_SYSTEM)) { // In non-headless system user mode, DO can be setup only if - // there's no non-system user - if (!mInjector.userManagerIsHeadlessSystemUserMode() - && mUserManager.getUserCount() > 1) { + // there's no non-system user. + // In headless system user mode, DO can be setup only if there are + // two users: the headless system user and the foreground user. + // If there could be multiple foreground users, this constraint should be modified. + + int maxNumberOfExistingUsers = isHeadlessSystemUserMode ? 2 : 1; + if (mUserManager.getUserCount() > maxNumberOfExistingUsers) { return CODE_NONSYSTEM_USER_EXISTS; } 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 8099eda9a0af..775276bd03f6 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 @@ -63,7 +63,6 @@ import android.util.DataUnit; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; import com.android.server.job.JobSchedulerService.Constants; -import com.android.server.job.JobServiceContext; import com.android.server.net.NetworkPolicyManagerInternal; import org.junit.Before; @@ -144,8 +143,7 @@ public class ConnectivityControllerTest { .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); final ConnectivityController controller = new ConnectivityController(mService); - when(mService.getMaxJobExecutionTimeMs(any())) - .thenReturn(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS); + when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L); // Slow network is too slow assertFalse(controller.isSatisfied(createJobStatus(job), net, diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index c4c9173536ad..b72121f096ba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -82,8 +82,6 @@ import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import com.android.server.PowerAllowlistInternal; import com.android.server.job.JobSchedulerService; -import com.android.server.job.JobSchedulerService.Constants; -import com.android.server.job.JobServiceContext; import com.android.server.job.JobStore; import com.android.server.job.controllers.QuotaController.ExecutionStats; import com.android.server.job.controllers.QuotaController.QcConstants; @@ -123,6 +121,7 @@ public class QuotaControllerTest { private BroadcastReceiver mChargingReceiver; private QuotaController mQuotaController; private QuotaController.QcConstants mQcConstants; + private JobSchedulerService.Constants mConstants = new JobSchedulerService.Constants(); private int mSourceUid; private PowerAllowlistInternal.TempAllowlistChangeListener mTempAllowlistListener; private IUidObserver mUidObserver; @@ -158,7 +157,7 @@ public class QuotaControllerTest { // Called in StateController constructor. when(mJobSchedulerService.getTestableContext()).thenReturn(mContext); when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService); - when(mJobSchedulerService.getConstants()).thenReturn(mock(Constants.class)); + when(mJobSchedulerService.getConstants()).thenReturn(mConstants); // Called in QuotaController constructor. IActivityManager activityManager = ActivityManager.getService(); spyOn(activityManager); @@ -1282,23 +1281,23 @@ public class QuotaControllerTest { } @Test - public void testGetMaxJobExecutionTimeLocked() { + public void testGetMaxJobExecutionTimeLocked_Regular() { mQuotaController.saveTimingSession(0, SOURCE_PACKAGE, createTimingSession(sElapsedRealtimeClock.millis() - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false); JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked", 0); - job.setStandbyBucket(RARE_INDEX); + setStandbyBucket(RARE_INDEX, job); setCharging(); synchronized (mQuotaController.mLock) { - assertEquals(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS, + assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, mQuotaController.getMaxJobExecutionTimeMsLocked((job))); } setDischarging(); setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); synchronized (mQuotaController.mLock) { - assertEquals(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS, + assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, mQuotaController.getMaxJobExecutionTimeMsLocked((job))); } @@ -1310,7 +1309,7 @@ public class QuotaControllerTest { } setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); synchronized (mQuotaController.mLock) { - assertEquals(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS, + assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, mQuotaController.getMaxJobExecutionTimeMsLocked((job))); mQuotaController.maybeStopTrackingJobLocked(job, null, false); } @@ -1322,6 +1321,81 @@ public class QuotaControllerTest { } } + @Test + public void testGetMaxJobExecutionTimeLocked_EJ() { + final long timeUsedMs = 3 * MINUTE_IN_MILLIS; + mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, + createTimingSession(sElapsedRealtimeClock.millis() - (6 * MINUTE_IN_MILLIS), + timeUsedMs, 5), true); + JobStatus job = createExpeditedJobStatus("testGetMaxJobExecutionTimeLocked_EJ", 0); + setStandbyBucket(RARE_INDEX, job); + mQuotaController.maybeStartTrackingJobLocked(job, null); + + setCharging(); + synchronized (mQuotaController.mLock) { + assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + } + + setDischarging(); + setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + synchronized (mQuotaController.mLock) { + assertEquals(mQcConstants.EJ_LIMIT_WORKING_MS / 2, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + } + + // Top-started job + setProcessState(ActivityManager.PROCESS_STATE_TOP); + synchronized (mQuotaController.mLock) { + mQuotaController.prepareForExecutionLocked(job); + } + setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); + synchronized (mQuotaController.mLock) { + assertEquals(mQcConstants.EJ_LIMIT_ACTIVE_MS / 2, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + mQuotaController.maybeStopTrackingJobLocked(job, null, false); + } + + setProcessState(ActivityManager.PROCESS_STATE_RECEIVER); + synchronized (mQuotaController.mLock) { + assertEquals(mQcConstants.EJ_LIMIT_RARE_MS - timeUsedMs, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + } + + // Test used quota rolling out of window. + synchronized (mQuotaController.mLock) { + mQuotaController.clearAppStatsLocked(SOURCE_USER_ID, SOURCE_PACKAGE); + } + mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, + createTimingSession(sElapsedRealtimeClock.millis() - mQcConstants.EJ_WINDOW_SIZE_MS, + timeUsedMs, 5), true); + + setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); + synchronized (mQuotaController.mLock) { + assertEquals(mQcConstants.EJ_LIMIT_WORKING_MS / 2, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + } + + // Top-started job + setProcessState(ActivityManager.PROCESS_STATE_TOP); + synchronized (mQuotaController.mLock) { + mQuotaController.maybeStartTrackingJobLocked(job, null); + mQuotaController.prepareForExecutionLocked(job); + } + setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND); + synchronized (mQuotaController.mLock) { + assertEquals(mQcConstants.EJ_LIMIT_ACTIVE_MS / 2, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + mQuotaController.maybeStopTrackingJobLocked(job, null, false); + } + + setProcessState(ActivityManager.PROCESS_STATE_RECEIVER); + synchronized (mQuotaController.mLock) { + assertEquals(mQcConstants.EJ_LIMIT_RARE_MS, + mQuotaController.getMaxJobExecutionTimeMsLocked(job)); + } + } + /** * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket * window. @@ -2508,7 +2582,7 @@ public class QuotaControllerTest { assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[WORKING_INDEX]); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]); assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]); - assertEquals(0, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); + assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]); assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs()); assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs()); assertEquals(1, mQuotaController.getEJTopAppTimeChunkSizeMs()); diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index f935bfcd9068..d663b649fbba 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -122,6 +122,7 @@ public class LockTaskControllerTest { @Mock private StatusBarManagerInternal mStatusBarManagerInternal; @Mock private TelecomManager mTelecomManager; @Mock private RecentTasks mRecentTasks; + @Mock private TaskChangeNotificationController mTaskChangeNotificationController; private LockTaskController mLockTaskController; private Context mContext; @@ -145,7 +146,7 @@ public class LockTaskControllerTest { mSupervisor.mRootWindowContainer = mRootWindowContainer; mLockTaskController = new LockTaskController(mContext, mSupervisor, - new ImmediatelyExecuteHandler()); + new ImmediatelyExecuteHandler(), mTaskChangeNotificationController); mLockTaskController.setWindowManager(mWindowManager); mLockTaskController.mStatusBarService = mStatusBarService; mLockTaskController.mDevicePolicyManager = mDevicePolicyManager; diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS index f35a318acbf7..b5561010e7f9 100644 --- a/tests/FlickerTests/OWNERS +++ b/tests/FlickerTests/OWNERS @@ -1,2 +1,3 @@ +# Bug component: 909476 include /services/core/java/com/android/server/wm/OWNERS natanieljr@google.com
\ No newline at end of file |