diff options
536 files changed, 8335 insertions, 31756 deletions
diff --git a/Android.bp b/Android.bp index 149b22355c58..cd110deb8a17 100644 --- a/Android.bp +++ b/Android.bp @@ -272,8 +272,6 @@ java_defaults { include_dirs: [ "frameworks/av/aidl", "frameworks/native/libs/permission/aidl", - // TODO: remove when moved to the below package - "frameworks/base/packages/ConnectivityT/framework-t/aidl-export", "packages/modules/Bluetooth/framework/aidl-export", "packages/modules/Connectivity/framework/aidl-export", "packages/modules/Media/apex/aidl/stable", @@ -531,8 +529,6 @@ stubs_defaults { include_dirs: [ "frameworks/av/aidl", "frameworks/native/libs/permission/aidl", - // TODO: remove when moved to the below package - "frameworks/base/packages/ConnectivityT/framework-t/aidl-export", "packages/modules/Bluetooth/framework/aidl-export", "packages/modules/Connectivity/framework/aidl-export", "packages/modules/Media/apex/aidl/stable", diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java index f822a188c99c..56811076e013 100644 --- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java @@ -245,4 +245,7 @@ public interface AppStandbyInternal { */ @Nullable String getAppStandbyConstant(@NonNull String key); + + /** Clears the last used timestamps data for the given {@code packageName}. */ + void clearLastUsedTimestampsForTest(@NonNull String packageName, @UserIdInt int userId); } diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 528be3ca5e4b..a09f39f26eab 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -348,7 +348,8 @@ public class AlarmManagerService extends SystemService { new SparseArray<>(); private AppStateTrackerImpl mAppStateTracker; - private boolean mAppStandbyParole; + @VisibleForTesting + boolean mAppStandbyParole; /** * A container to keep rolling window history of previous times when an alarm was sent to @@ -1891,6 +1892,9 @@ public class AlarmManagerService extends SystemService { (AppStateTrackerImpl) LocalServices.getService(AppStateTracker.class); mAppStateTracker.addListener(mForceAppStandbyListener); + final BatteryManager bm = getContext().getSystemService(BatteryManager.class); + mAppStandbyParole = bm.isCharging(); + mClockReceiver.scheduleTimeTickEvent(); mClockReceiver.scheduleDateChangedEvent(); } 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 405b12d6d13a..dfd019d9fa9e 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -265,31 +265,22 @@ class JobConcurrencyManager { ) ); - /** - * This array essentially stores the state of mActiveServices array. - * The ith index stores the job present on the ith JobServiceContext. - * We manipulate this array until we arrive at what jobs should be running on - * what JobServiceContext. - */ - JobStatus[] mRecycledAssignContextIdToJobMap = new JobStatus[MAX_JOB_CONTEXTS_COUNT]; - - boolean[] mRecycledSlotChanged = new boolean[MAX_JOB_CONTEXTS_COUNT]; - - int[] mRecycledPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT]; - - int[] mRecycledWorkTypeForContext = new int[MAX_JOB_CONTEXTS_COUNT]; + private final ArraySet<ContextAssignment> mRecycledChanged = new ArraySet<>(); + private final ArraySet<ContextAssignment> mRecycledIdle = new ArraySet<>(); + private final ArraySet<ContextAssignment> mRecycledPreferredUidOnly = new ArraySet<>(); + private final ArraySet<ContextAssignment> mRecycledStoppable = new ArraySet<>(); - String[] mRecycledPreemptReasonForContext = new String[MAX_JOB_CONTEXTS_COUNT]; - - int[] mRecycledPreemptReasonCodeForContext = new int[MAX_JOB_CONTEXTS_COUNT]; - - String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT]; + private final Pools.Pool<ContextAssignment> mContextAssignmentPool = + new Pools.SimplePool<>(MAX_JOB_CONTEXTS_COUNT); /** - * Set of JobServiceContexts that we use to run jobs. + * Set of JobServiceContexts that are actively running jobs. */ final List<JobServiceContext> mActiveServices = new ArrayList<>(); + /** Set of JobServiceContexts that aren't currently running any jobs. */ + final ArraySet<JobServiceContext> mIdleContexts = new ArraySet<>(); + private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>(); private final WorkCountTracker mWorkCountTracker = new WorkCountTracker(); @@ -378,7 +369,7 @@ class JobConcurrencyManager { final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface( ServiceManager.getService(BatteryStats.SERVICE_NAME)); for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { - mActiveServices.add( + mIdleContexts.add( new JobServiceContext(mService, this, batteryStats, mService.mJobPackageTracker, mContext.getMainLooper())); } @@ -581,13 +572,10 @@ class JobConcurrencyManager { final List<JobServiceContext> activeServices = mActiveServices; // To avoid GC churn, we recycle the arrays. - JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap; - boolean[] slotChanged = mRecycledSlotChanged; - int[] preferredUidForContext = mRecycledPreferredUidForContext; - int[] workTypeForContext = mRecycledWorkTypeForContext; - String[] preemptReasonForContext = mRecycledPreemptReasonForContext; - int[] preemptReasonCodeForContext = mRecycledPreemptReasonCodeForContext; - String[] shouldStopJobReason = mRecycledShouldStopJobReason; + final ArraySet<ContextAssignment> changed = mRecycledChanged; + final ArraySet<ContextAssignment> idle = mRecycledIdle; + final ArraySet<ContextAssignment> preferredUidOnly = mRecycledPreferredUidOnly; + final ArraySet<ContextAssignment> stoppable = mRecycledStoppable; updateCounterConfigLocked(); // Reset everything since we'll re-evaluate the current state. @@ -598,23 +586,50 @@ class JobConcurrencyManager { // shouldStopRunningJobLocked(). updateNonRunningPrioritiesLocked(pendingJobQueue, true); - for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { - final JobServiceContext js = activeServices.get(i); - final JobStatus status = js.getRunningJobLocked(); + final int numRunningJobs = activeServices.size(); + for (int i = 0; i < numRunningJobs; ++i) { + final JobServiceContext jsc = activeServices.get(i); + final JobStatus js = jsc.getRunningJobLocked(); + + ContextAssignment assignment = mContextAssignmentPool.acquire(); + if (assignment == null) { + assignment = new ContextAssignment(); + } + + assignment.context = jsc; + + if (js != null) { + mWorkCountTracker.incrementRunningJobCount(jsc.getRunningJobWorkType()); + assignment.workType = jsc.getRunningJobWorkType(); + } + + assignment.preferredUid = jsc.getPreferredUid(); + if ((assignment.shouldStopJobReason = shouldStopRunningJobLocked(jsc)) != null) { + stoppable.add(assignment); + } else { + preferredUidOnly.add(assignment); + } + } + for (int i = numRunningJobs; i < MAX_JOB_CONTEXTS_COUNT; ++i) { + final JobServiceContext jsc; + final int numIdleContexts = mIdleContexts.size(); + if (numIdleContexts > 0) { + jsc = mIdleContexts.removeAt(numIdleContexts - 1); + } else { + Slog.wtf(TAG, "Had fewer than " + MAX_JOB_CONTEXTS_COUNT + " in existence"); + jsc = createNewJobServiceContext(); + } - if ((contextIdToJobMap[i] = status) != null) { - mWorkCountTracker.incrementRunningJobCount(js.getRunningJobWorkType()); - workTypeForContext[i] = js.getRunningJobWorkType(); + ContextAssignment assignment = mContextAssignmentPool.acquire(); + if (assignment == null) { + assignment = new ContextAssignment(); } - slotChanged[i] = false; - preferredUidForContext[i] = js.getPreferredUid(); - preemptReasonForContext[i] = null; - preemptReasonCodeForContext[i] = JobParameters.STOP_REASON_UNDEFINED; - shouldStopJobReason[i] = shouldStopRunningJobLocked(js); + assignment.context = jsc; + idle.add(assignment); } if (DEBUG) { - Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs initial")); + Slog.d(TAG, printAssignments("running jobs initial", stoppable, preferredUidOnly)); } mWorkCountTracker.onCountDone(); @@ -626,125 +641,155 @@ class JobConcurrencyManager { continue; } - // Find an available slot for nextPending. The context should be available OR - // it should have the lowest bias among all running jobs - // (sharing the same Uid as nextPending) - int minBiasForPreemption = Integer.MAX_VALUE; - int selectedContextId = -1; - int allWorkTypes = getJobWorkTypes(nextPending); - int workType = mWorkCountTracker.canJobStart(allWorkTypes); - boolean startingJob = false; - int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED; - String preemptReason = null; + // Find an available slot for nextPending. The context should be one of the following: + // 1. Unused + // 2. Its job should have used up its minimum execution guarantee so it + // 3. Its job should have the lowest bias among all running jobs (sharing the same UID + // as nextPending) + ContextAssignment selectedContext = null; + final int allWorkTypes = getJobWorkTypes(nextPending); final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending); - // 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]; - if (job == null) { - final boolean preferredUidOkay = (preferredUid == nextPending.getUid()) - || (preferredUid == JobServiceContext.NO_PREFERRED_UID); - - if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) { - // This slot is free, and we haven't yet hit the limit on - // concurrent jobs... we can just throw the job in to here. - selectedContextId = j; - startingJob = true; - break; - } - // No job on this context, but nextPending can't run here because - // the context has a preferred Uid or we have reached the limit on - // concurrent jobs. - continue; + boolean startingJob = false; + if (idle.size() > 0) { + final int idx = idle.size() - 1; + final ContextAssignment assignment = idle.valueAt(idx); + final boolean preferredUidOkay = (assignment.preferredUid == nextPending.getUid()) + || (assignment.preferredUid == JobServiceContext.NO_PREFERRED_UID); + int workType = mWorkCountTracker.canJobStart(allWorkTypes); + if (preferredUidOkay && pkgConcurrencyOkay && workType != WORK_TYPE_NONE) { + // This slot is free, and we haven't yet hit the limit on + // concurrent jobs... we can just throw the job in to here. + selectedContext = assignment; + startingJob = true; + idle.removeAt(idx); + assignment.newJob = nextPending; + assignment.newWorkType = workType; } - if (job.getUid() != nextPending.getUid()) { + } + if (selectedContext == null) { + for (int s = stoppable.size() - 1; s >= 0; --s) { + ContextAssignment assignment = stoppable.valueAt(s); + JobStatus runningJob = assignment.context.getRunningJobLocked(); // Maybe stop the job if it has had its day in the sun. Don't let a different // app preempt jobs started for TOP apps though. - final String reason = shouldStopJobReason[j]; - if (job.lastEvaluatedBias < JobInfo.BIAS_TOP_APP - && 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; - preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE; + if (runningJob.lastEvaluatedBias < JobInfo.BIAS_TOP_APP + && assignment.shouldStopJobReason != null) { + int replaceWorkType = mWorkCountTracker.canJobStart(allWorkTypes, + assignment.context.getRunningJobWorkType()); + if (replaceWorkType != 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. + assignment.preemptReason = assignment.shouldStopJobReason; + assignment.preemptReasonCode = JobParameters.STOP_REASON_DEVICE_STATE; + selectedContext = assignment; + stoppable.removeAt(s); + assignment.newJob = nextPending; + assignment.newWorkType = replaceWorkType; + // Don't preserve the UID since we're stopping the job because + // something is pending (eg. EJs). + assignment.context.clearPreferredUid(); + break; + } } - continue; } + } + if (selectedContext == null) { + int lowestBiasSeen = Integer.MAX_VALUE; + for (int p = preferredUidOnly.size() - 1; p >= 0; --p) { + final ContextAssignment assignment = preferredUidOnly.valueAt(p); + final JobStatus runningJob = assignment.context.getRunningJobLocked(); + if (runningJob.getUid() != nextPending.getUid()) { + continue; + } + final int jobBias = mService.evaluateJobBiasLocked(runningJob); + if (jobBias >= nextPending.lastEvaluatedBias) { + continue; + } - final int jobBias = mService.evaluateJobBiasLocked(job); - if (jobBias >= nextPending.lastEvaluatedBias) { - continue; + if (selectedContext == null || lowestBiasSeen > jobBias) { + // Step down the preemption threshold - wind up replacing + // the lowest-bias running job + lowestBiasSeen = jobBias; + selectedContext = assignment; + assignment.preemptReason = "higher bias job found"; + assignment.preemptReasonCode = JobParameters.STOP_REASON_PREEMPT; + // In this case, we're just going to preempt a low bias job, we're not + // actually starting a job, so don't set startingJob to true. + } } - - if (minBiasForPreemption > jobBias) { - // Step down the preemption threshold - wind up replacing - // the lowest-bias running job - minBiasForPreemption = jobBias; - selectedContextId = j; - preemptReason = "higher bias job found"; - preemptReasonCode = JobParameters.STOP_REASON_PREEMPT; - // In this case, we're just going to preempt a low bias job, we're not - // actually starting a job, so don't set startingJob. + if (selectedContext != null) { + selectedContext.newJob = nextPending; + preferredUidOnly.remove(selectedContext); } } final PackageStats packageStats = getPkgStatsLocked( nextPending.getSourceUserId(), nextPending.getSourcePackageName()); - if (selectedContextId != -1) { - contextIdToJobMap[selectedContextId] = nextPending; - slotChanged[selectedContextId] = true; - preemptReasonCodeForContext[selectedContextId] = preemptReasonCode; - preemptReasonForContext[selectedContextId] = preemptReason; + if (selectedContext != null) { + changed.add(selectedContext); packageStats.adjustStagedCount(true, nextPending.shouldTreatAsExpeditedJob()); } if (startingJob) { // Increase the counters when we're going to start a job. - workTypeForContext[selectedContextId] = workType; - mWorkCountTracker.stageJob(workType, allWorkTypes); + mWorkCountTracker.stageJob(selectedContext.newWorkType, allWorkTypes); mActivePkgStats.add( nextPending.getSourceUserId(), nextPending.getSourcePackageName(), packageStats); } } if (DEBUG) { - Slog.d(TAG, printContextIdToJobMap(contextIdToJobMap, "running jobs final")); + Slog.d(TAG, printAssignments("running jobs final", + stoppable, preferredUidOnly, changed)); Slog.d(TAG, "assignJobsToContexts: " + mWorkCountTracker.toString()); } - for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) { - boolean preservePreferredUid = false; - if (slotChanged[i]) { - JobStatus js = activeServices.get(i).getRunningJobLocked(); - if (js != null) { - if (DEBUG) { - Slog.d(TAG, "preempting job: " - + activeServices.get(i).getRunningJobLocked()); - } - // preferredUid will be set to uid of currently running job. - activeServices.get(i).cancelExecutingJobLocked( - preemptReasonCodeForContext[i], - JobParameters.INTERNAL_STOP_REASON_PREEMPT, preemptReasonForContext[i]); - // Only preserve the UID if we're preempting for the same UID. If we're stopping - // the job because something is pending (eg. EJs), then we shouldn't preserve - // the UID. - preservePreferredUid = - preemptReasonCodeForContext[i] == JobParameters.STOP_REASON_PREEMPT; - } else { - final JobStatus pendingJob = contextIdToJobMap[i]; - if (DEBUG) { - Slog.d(TAG, "About to run job on context " - + i + ", job: " + pendingJob); - } - startJobLocked(activeServices.get(i), pendingJob, workTypeForContext[i]); + for (int c = changed.size() - 1; c >= 0; --c) { + final ContextAssignment assignment = changed.valueAt(c); + final JobStatus js = assignment.context.getRunningJobLocked(); + if (js != null) { + if (DEBUG) { + Slog.d(TAG, "preempting job: " + js); } - } - if (!preservePreferredUid) { - activeServices.get(i).clearPreferredUid(); - } - } + // preferredUid will be set to uid of currently running job. + assignment.context.cancelExecutingJobLocked( + assignment.preemptReasonCode, + JobParameters.INTERNAL_STOP_REASON_PREEMPT, assignment.preemptReason); + } else { + final JobStatus pendingJob = assignment.newJob; + if (DEBUG) { + Slog.d(TAG, "About to run job on context " + + assignment.context.getId() + ", job: " + pendingJob); + } + startJobLocked(assignment.context, pendingJob, assignment.newWorkType); + } + + assignment.clear(); + mContextAssignmentPool.release(assignment); + } + for (int s = stoppable.size() - 1; s >= 0; --s) { + final ContextAssignment assignment = stoppable.valueAt(s); + assignment.context.clearPreferredUid(); + assignment.clear(); + mContextAssignmentPool.release(assignment); + } + for (int p = preferredUidOnly.size() - 1; p >= 0; --p) { + final ContextAssignment assignment = preferredUidOnly.valueAt(p); + assignment.context.clearPreferredUid(); + assignment.clear(); + mContextAssignmentPool.release(assignment); + } + for (int i = idle.size() - 1; i >= 0; --i) { + final ContextAssignment assignment = idle.valueAt(i); + mIdleContexts.add(assignment.context); + assignment.context.clearPreferredUid(); + assignment.clear(); + mContextAssignmentPool.release(assignment); + } + changed.clear(); + idle.clear(); + stoppable.clear(); + preferredUidOnly.clear(); mWorkCountTracker.resetStagingCount(); mActivePkgStats.forEach(mPackageStatsStagingCountClearer); noteConcurrency(); @@ -787,7 +832,7 @@ class JobConcurrencyManager { @GuardedBy("mLock") private void stopLongRunningJobsLocked(@NonNull String debugReason) { - for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; ++i) { + for (int i = 0; i < mActiveServices.size(); ++i) { final JobServiceContext jsc = mActiveServices.get(i); final JobStatus jobStatus = jsc.getRunningJobLocked(); @@ -931,6 +976,8 @@ class JobConcurrencyManager { } } else { mRunningJobs.add(jobStatus); + mActiveServices.add(worker); + mIdleContexts.remove(worker); mWorkCountTracker.onJobStarted(workType); packageStats.adjustRunningCount(true, jobStatus.shouldTreatAsExpeditedJob()); mActivePkgStats.add( @@ -950,6 +997,8 @@ class JobConcurrencyManager { @WorkType final int workType) { mWorkCountTracker.onJobFinished(workType); mRunningJobs.remove(jobStatus); + mActiveServices.remove(worker); + mIdleContexts.add(worker); final PackageStats packageStats = mActivePkgStats.get(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName()); if (packageStats == null) { @@ -1093,7 +1142,7 @@ class JobConcurrencyManager { /** * 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 + * be stopped if there are 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 @@ -1202,6 +1251,14 @@ class JobConcurrencyManager { return foundSome; } + @NonNull + private JobServiceContext createNewJobServiceContext() { + return new JobServiceContext(mService, this, + IBatteryStats.Stub.asInterface( + ServiceManager.getService(BatteryStats.SERVICE_NAME)), + mService.mJobPackageTracker, mContext.getMainLooper()); + } + @GuardedBy("mLock") private String printPendingQueueLocked() { StringBuilder s = new StringBuilder("Pending queue: "); @@ -1218,13 +1275,26 @@ class JobConcurrencyManager { return s.toString(); } - private static String printContextIdToJobMap(JobStatus[] map, String initial) { - StringBuilder s = new StringBuilder(initial + ": "); - for (int i=0; i<map.length; i++) { - s.append("(") - .append(map[i] == null? -1: map[i].getJobId()) - .append(map[i] == null? -1: map[i].getUid()) - .append(")" ); + private static String printAssignments(String header, ArraySet<ContextAssignment>... list) { + final StringBuilder s = new StringBuilder(header + ": "); + for (int l = 0; l < list.length; ++l) { + ArraySet<ContextAssignment> assignments = list[l]; + for (int c = 0; c < assignments.size(); ++c) { + final ContextAssignment assignment = assignments.valueAt(c); + final JobStatus job = assignment.newJob == null + ? assignment.context.getRunningJobLocked() : assignment.newJob; + + if (l > 0 || c > 0) { + s.append(" "); + } + s.append("(").append(assignment.context.getId()).append("="); + if (job == null) { + s.append("nothing"); + } else { + s.append(job.getJobId()).append("/").append(job.getUid()); + } + s.append(")"); + } } return s.toString(); } @@ -1327,10 +1397,13 @@ class JobConcurrencyManager { } @GuardedBy("mLock") - void dumpActiveJobsLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate, + void dumpContextInfoLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate, long nowElapsed, long nowUptime) { pw.println("Active jobs:"); pw.increaseIndent(); + if (mActiveServices.size() == 0) { + pw.println("N/A"); + } for (int i = 0; i < mActiveServices.size(); i++) { JobServiceContext jsc = mActiveServices.get(i); final JobStatus job = jsc.getRunningJobLocked(); @@ -1339,7 +1412,8 @@ class JobConcurrencyManager { continue; } - pw.print("Slot #"); pw.print(i); pw.print(": "); + pw.print("Slot #"); pw.print(i); + pw.print("(ID="); pw.print(jsc.getId()); pw.print("): "); jsc.dumpLocked(pw, nowElapsed); if (job != null) { @@ -1361,6 +1435,19 @@ class JobConcurrencyManager { } } pw.decreaseIndent(); + + pw.println(); + pw.print("Idle contexts ("); + pw.print(mIdleContexts.size()); + pw.println("):"); + pw.increaseIndent(); + for (int i = 0; i < mIdleContexts.size(); i++) { + JobServiceContext jsc = mIdleContexts.valueAt(i); + + pw.print("ID="); pw.print(jsc.getId()); pw.print(": "); + jsc.dumpLocked(pw, nowElapsed); + } + pw.decreaseIndent(); } public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) { @@ -1989,4 +2076,26 @@ class JobConcurrencyManager { pw.println("}"); } } + + private static final class ContextAssignment { + public JobServiceContext context; + public int preferredUid = JobServiceContext.NO_PREFERRED_UID; + public int workType = WORK_TYPE_NONE; + public String preemptReason; + public int preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED; + public String shouldStopJobReason; + public JobStatus newJob; + public int newWorkType = WORK_TYPE_NONE; + + void clear() { + context = null; + preferredUid = JobServiceContext.NO_PREFERRED_UID; + workType = WORK_TYPE_NONE; + preemptReason = null; + preemptReasonCode = JobParameters.STOP_REASON_UNDEFINED; + shouldStopJobReason = null; + newJob = null; + newWorkType = WORK_TYPE_NONE; + } + } } 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 2028be738238..0b8162a3df95 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -3770,7 +3770,7 @@ public class JobSchedulerService extends com.android.server.SystemService pw.decreaseIndent(); pw.println(); - mConcurrencyManager.dumpActiveJobsLocked(pw, predicate, nowElapsed, nowUptime); + mConcurrencyManager.dumpContextInfoLocked(pw, predicate, nowElapsed, nowUptime); pw.println(); boolean recentPrinted = false; 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 00d1bfffd9a6..54e0a4c6663c 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -433,6 +433,10 @@ public final class JobServiceContext implements ServiceConnection { mPreferredUid = NO_PREFERRED_UID; } + int getId() { + return hashCode(); + } + long getExecutionStartTimeElapsed() { return mExecutionStartTimeElapsed; } diff --git a/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java index f91472bdd160..daf1ee10130d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java +++ b/apex/jobscheduler/service/java/com/android/server/job/PendingJobQueue.java @@ -182,8 +182,10 @@ class PendingJobQueue { if (earliestQueue != null) { final JobStatus job = earliestQueue.next(); // Change the front of the queue if we've pulled pullLimit jobs from the current head + // or we're dealing with test jobs // or the current head has no more jobs to provide. if (++mPullCount >= pullLimit + || (job != null && earliestQueue.peekNextOverrideState() != job.overrideState) || earliestQueue.peekNextTimestamp() == AppJobQueue.NO_NEXT_TIMESTAMP) { mOrderedQueues.poll(); if (earliestQueue.peekNextTimestamp() != AppJobQueue.NO_NEXT_TIMESTAMP) { diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java index 2e3b377d08a5..80f3fea1907c 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java @@ -623,7 +623,8 @@ public class AppIdleHistory { * @param elapsedRealtime current time * @param screenTimeThresholds Array of screen times, in ascending order, first one is 0 * @param elapsedTimeThresholds Array of elapsed time, in ascending order, first one is 0 - * @return The index whose values the app's used time exceeds (in both arrays) + * @return The index whose values the app's used time exceeds (in both arrays) or {@code -1} to + * indicate that the app has never been used. */ int getThresholdIndex(String packageName, int userId, long elapsedRealtime, long[] screenTimeThresholds, long[] elapsedTimeThresholds) { @@ -631,14 +632,13 @@ public class AppIdleHistory { AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, false); // If we don't have any state for the app, assume never used - if (appUsageHistory == null) return screenTimeThresholds.length - 1; + if (appUsageHistory == null || appUsageHistory.lastUsedElapsedTime < 0 + || appUsageHistory.lastUsedScreenTime < 0) { + return -1; + } - long screenOnDelta = appUsageHistory.lastUsedScreenTime >= 0 - ? getScreenOnTime(elapsedRealtime) - appUsageHistory.lastUsedScreenTime - : Long.MAX_VALUE; - long elapsedDelta = appUsageHistory.lastUsedElapsedTime >= 0 - ? getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedElapsedTime - : Long.MAX_VALUE; + long screenOnDelta = getScreenOnTime(elapsedRealtime) - appUsageHistory.lastUsedScreenTime; + long elapsedDelta = getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedElapsedTime; if (DEBUG) Slog.d(TAG, packageName + " lastUsedScreen=" + appUsageHistory.lastUsedScreenTime @@ -686,6 +686,17 @@ public class AppIdleHistory { Integer.toString(userId)), APP_IDLE_FILENAME); } + void clearLastUsedTimestamps(String packageName, int userId) { + ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); + AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, + SystemClock.elapsedRealtime(), false /* create */); + if (appUsageHistory != null) { + appUsageHistory.lastUsedByUserElapsedTime = Integer.MIN_VALUE; + appUsageHistory.lastUsedElapsedTime = Integer.MIN_VALUE; + appUsageHistory.lastUsedScreenTime = Integer.MIN_VALUE; + } + } + /** * Check if App Idle File exists on disk * @param userId diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 502913063a00..1e4ecc2adfb2 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -898,11 +898,9 @@ public class AppStandbyController } } - final long elapsedLastUsedByUserTimeDelta = app.lastUsedByUserElapsedTime >= 0 - ? elapsedTimeAdjusted - app.lastUsedByUserElapsedTime - : Long.MAX_VALUE; - if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime - && elapsedLastUsedByUserTimeDelta + if (app.lastUsedByUserElapsedTime >= 0 + && app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime + && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime >= mInjector.getAutoRestrictedBucketDelayMs()) { newBucket = STANDBY_BUCKET_RESTRICTED; reason = app.lastRestrictReason; @@ -974,7 +972,7 @@ public class AppStandbyController long elapsedRealtime) { int bucketIndex = mAppIdleHistory.getThresholdIndex(packageName, userId, elapsedRealtime, mAppStandbyScreenThresholds, mAppStandbyElapsedThresholds); - return THRESHOLD_BUCKETS[bucketIndex]; + return bucketIndex >= 0 ? THRESHOLD_BUCKETS[bucketIndex] : STANDBY_BUCKET_NEVER; } private void notifyBatteryStats(String packageName, int userId, boolean idle) { @@ -1857,6 +1855,13 @@ public class AppStandbyController } @Override + public void clearLastUsedTimestampsForTest(@NonNull String packageName, @UserIdInt int userId) { + synchronized (mAppIdleLock) { + mAppIdleHistory.clearLastUsedTimestamps(packageName, userId); + } + } + + @Override public void flushToDisk() { synchronized (mAppIdleLock) { mAppIdleHistory.writeAppIdleTimes(mInjector.elapsedRealtime()); @@ -2096,6 +2101,13 @@ public class AppStandbyController .sendToTarget(); } + @VisibleForTesting + AppIdleHistory getAppIdleHistoryForTest() { + synchronized (mAppIdleLock) { + return mAppIdleHistory; + } + } + @Override public void dumpUsers(IndentingPrintWriter idpw, int[] userIds, List<String> pkgs) { synchronized (mAppIdleLock) { diff --git a/core/api/current.txt b/core/api/current.txt index 226c7d58d911..d03ab96fbf46 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8,9 +8,6 @@ package android { public static final class Manifest.permission { ctor public Manifest.permission(); field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER"; - field public static final String ACCESS_ADSERVICES_ATTRIBUTION = "android.permission.ACCESS_ADSERVICES_ATTRIBUTION"; - field public static final String ACCESS_ADSERVICES_CUSTOM_AUDIENCES = "android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES"; - field public static final String ACCESS_ADSERVICES_TOPICS = "android.permission.ACCESS_ADSERVICES_TOPICS"; field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION"; field public static final String ACCESS_BLOBS_ACROSS_USERS = "android.permission.ACCESS_BLOBS_ACROSS_USERS"; field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES"; @@ -12331,6 +12328,7 @@ package android.content.pm { method @Nullable public java.util.Set<java.lang.String> getCategories(); method @Nullable public CharSequence getDisabledMessage(); method public int getDisabledReason(); + method public int getExcludedFromSurfaces(); method @Nullable public android.os.PersistableBundle getExtras(); method @NonNull public String getId(); method @Nullable public android.content.Intent getIntent(); @@ -12347,8 +12345,8 @@ package android.content.pm { method public boolean isDeclaredInManifest(); method public boolean isDynamic(); method public boolean isEnabled(); + method public boolean isExcludedFromSurfaces(int); method public boolean isImmutable(); - method public boolean isIncludedIn(int); method public boolean isPinned(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR; @@ -24461,6 +24459,7 @@ package android.media.metrics { method public void close(); method @NonNull public android.media.metrics.LogSessionId getSessionId(); method public void reportBundleMetrics(@NonNull android.os.PersistableBundle); + field public static final String KEY_STATSD_ATOM = "bundlesession-statsd-atom"; } public final class EditingSession implements java.lang.AutoCloseable { @@ -24484,6 +24483,7 @@ package android.media.metrics { method @NonNull public android.media.metrics.PlaybackSession createPlaybackSession(); method @NonNull public android.media.metrics.RecordingSession createRecordingSession(); method @NonNull public android.media.metrics.TranscodingSession createTranscodingSession(); + method @NonNull public void releaseSessionId(@NonNull String); field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 57107c286b89..da0ad2cd8302 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1108,7 +1108,7 @@ package android.app.admin { method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, android.Manifest.permission.PROVISION_DEMO_DEVICE}) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException; - method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @RequiresPermission(android.Manifest.permission.TRIGGER_LOST_MODE) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException; method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied(); method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean); @@ -1195,13 +1195,16 @@ package android.app.admin { public static final class DevicePolicyResources.Strings { } - public static final class DevicePolicyResources.Strings.PermissionController { - field public static final String BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE = "PermissionController.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE"; - field public static final String BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionController.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE"; - field public static final String FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionController.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE"; - field public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE = "PermissionController.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE"; - field public static final String LOCATION_AUTO_GRANTED_MESSAGE = "PermissionController.LOCATION_AUTO_GRANTED_MESSAGE"; - field public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = "PermissionController.WORK_PROFILE_DEFAULT_APPS_TITLE"; + public static final class DevicePolicyResources.Strings.DefaultAppSettings { + field public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE = "DefaultAppSettings.HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE"; + field public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = "DefaultAppSettings.WORK_PROFILE_DEFAULT_APPS_TITLE"; + } + + public static final class DevicePolicyResources.Strings.PermissionSettings { + field public static final String BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE = "PermissionSettings.BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE"; + field public static final String BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionSettings.BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE"; + field public static final String FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE = "PermissionSettings.FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE"; + field public static final String LOCATION_AUTO_GRANTED_MESSAGE = "PermissionSettings.LOCATION_AUTO_GRANTED_MESSAGE"; } public class DevicePolicyResourcesManager { @@ -11813,10 +11816,10 @@ package android.service.translation { package android.service.trust { public final class GrantTrustResult implements android.os.Parcelable { + ctor public GrantTrustResult(int); method public int describeContents(); method public int getStatus(); method @NonNull public static String statusToString(int); - method @NonNull public static android.service.trust.GrantTrustResult withStatus(int); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.trust.GrantTrustResult> CREATOR; field public static final int STATUS_UNKNOWN = 0; // 0x0 @@ -13375,7 +13378,6 @@ package android.telephony { } public class TelephonyManager { - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addCarrierPrivilegesListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String); @@ -13476,7 +13478,6 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot(); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerCarrierPrivilegesCallback(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CarrierPrivilegesCallback); - method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeCarrierPrivilegesListener(@NonNull android.telephony.TelephonyManager.CarrierPrivilegesListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>); @@ -13637,10 +13638,6 @@ package android.telephony { method public default void onCarrierServiceChanged(@Nullable String, int); } - @Deprecated public static interface TelephonyManager.CarrierPrivilegesListener { - method @Deprecated public void onCarrierPrivilegesChanged(@NonNull java.util.List<java.lang.String>, @NonNull int[]); - } - public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception { ctor public TelephonyManager.ModemActivityInfoException(int); method public int getErrorCode(); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index a28b3e9fc545..5eda587cf7c8 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5707,7 +5707,6 @@ public class Activity extends ContextThemeWrapper * their launch had come from the original activity. * @param intent The Intent to start. * @param options ActivityOptions or null. - * @param permissionToken Token received from the system that permits this call to be made. * @param ignoreTargetSecurity If true, the activity manager will not check whether the * caller it is doing the start is, is actually allowed to start the target activity. * If you set this to true, you must set an explicit component in the Intent and do any @@ -5716,18 +5715,18 @@ public class Activity extends ContextThemeWrapper * @hide */ public void startActivityAsCaller(Intent intent, @Nullable Bundle options, - IBinder permissionToken, boolean ignoreTargetSecurity, int userId) { - startActivityAsCaller(intent, options, permissionToken, ignoreTargetSecurity, userId, -1); + boolean ignoreTargetSecurity, int userId) { + startActivityAsCaller(intent, options, ignoreTargetSecurity, userId, -1); } /** - * @see #startActivityAsCaller(Intent, Bundle, IBinder, boolean, int) + * @see #startActivityAsCaller(Intent, Bundle, boolean, int) * @param requestCode The request code used for returning a result or -1 if no result should be * returned. * @hide */ public void startActivityAsCaller(Intent intent, @Nullable Bundle options, - IBinder permissionToken, boolean ignoreTargetSecurity, int userId, int requestCode) { + boolean ignoreTargetSecurity, int userId, int requestCode) { if (mParent != null) { throw new RuntimeException("Can't be called from a child"); } @@ -5735,8 +5734,7 @@ public class Activity extends ContextThemeWrapper Instrumentation.ActivityResult ar = mInstrumentation.execStartActivityAsCaller( this, mMainThread.getApplicationThread(), mToken, this, - intent, requestCode, options, permissionToken, ignoreTargetSecurity, - userId); + intent, requestCode, options, ignoreTargetSecurity, userId); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 5b05b45d05db..88844b516726 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4890,6 +4890,11 @@ public class ActivityManager { } /** @hide */ + public static boolean isProcStateConsideredInteraction(@ProcessState int procState) { + return (procState <= PROCESS_STATE_TOP || procState == PROCESS_STATE_BOUND_TOP); + } + + /** @hide */ public static String procStateToString(int procState) { final String procStateStr; switch (procState) { diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 9fe8e792681c..95ac799e53d1 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -630,8 +630,9 @@ public abstract class ActivityManagerInternal { /** * Delete uid from the ActivityManagerService PendingStartActivityUids list. * @param uid uid + * @param nowElapsed starting time of updateOomAdj */ - public abstract void deletePendingTopUid(int uid); + public abstract void deletePendingTopUid(int uid, long nowElapsed); /** * Is the uid in ActivityManagerService PendingStartActivityUids list? @@ -684,6 +685,11 @@ public abstract class ActivityManagerInternal { public abstract @TempAllowListType int getPushMessagingOverQuotaBehavior(); /** + * Return the startForeground() grace period after calling startForegroundService(). + */ + public abstract int getServiceStartForegroundTimeout(); + + /** * Returns the capability of the given uid */ public abstract @ProcessCapability int getUidCapability(int uid); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 0d8103675cc2..0f54ce5f7a91 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -361,6 +361,10 @@ public class ActivityOptions extends ComponentOptions { private static final String KEY_LAUNCH_INTO_PIP_PARAMS = "android.activity.launchIntoPipParams"; + /** See {@link #setDismissKeyguardIfInsecure()}. */ + private static final String KEY_DISMISS_KEYGUARD_IF_INSECURE = + "android.activity.dismissKeyguardIfInsecure"; + /** * @see #setLaunchCookie * @hide @@ -457,6 +461,7 @@ public class ActivityOptions extends ComponentOptions { private boolean mLaunchedFromBubble; private boolean mTransientLaunch; private PictureInPictureParams mLaunchIntoPipParams; + private boolean mDismissKeyguardIfInsecure; /** * Create an ActivityOptions specifying a custom animation to run when @@ -1254,6 +1259,7 @@ public class ActivityOptions extends ComponentOptions { mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS); mIsEligibleForLegacyPermissionPrompt = opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE); + mDismissKeyguardIfInsecure = opts.getBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE); } /** @@ -1850,6 +1856,27 @@ public class ActivityOptions extends ComponentOptions { } /** + * Sets whether the insecure keyguard should go away when this activity launches. In case the + * keyguard is secure, this option will be ignored. + * + * @see Activity#setShowWhenLocked(boolean) + * @see android.R.attr#showWhenLocked + * @hide + */ + public void setDismissKeyguardIfInsecure() { + mDismissKeyguardIfInsecure = true; + } + + /** + * @see #setDismissKeyguardIfInsecure() + * @return whether the insecure keyguard should go away when the activity launches. + * @hide + */ + public boolean getDismissKeyguardIfInsecure() { + return mDismissKeyguardIfInsecure; + } + + /** * Update the current values in this ActivityOptions from those supplied * in <var>otherOptions</var>. Any values * defined in <var>otherOptions</var> replace those in the base options. @@ -2110,6 +2137,9 @@ public class ActivityOptions extends ComponentOptions { b.putBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE, mIsEligibleForLegacyPermissionPrompt); } + if (mDismissKeyguardIfInsecure) { + b.putBoolean(KEY_DISMISS_KEYGUARD_IF_INSECURE, mDismissKeyguardIfInsecure); + } return b; } diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index a83662592513..6fc0c260d89e 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -106,14 +106,6 @@ public class ActivityTaskManager { RESIZE_MODE_PRESERVE_WINDOW | RESIZE_MODE_FORCED; /** - * Extra included on intents that are delegating the call to - * ActivityManager#startActivityAsCaller to another app. This token is necessary for that call - * to succeed. Type is IBinder. - * @hide - */ - public static final String EXTRA_PERMISSION_TOKEN = "android.app.extra.PERMISSION_TOKEN"; - - /** * Extra included on intents that contain an EXTRA_INTENT, with options that the contained * intent may want to be started with. Type is Bundle. * TODO: remove once the ChooserActivity moves to systemui diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index ef9a2f273348..87b2417af53f 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -141,7 +141,7 @@ interface IActivityTaskManager { int startActivityAsCaller(in IApplicationThread caller, in String callingPackage, in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho, int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options, - IBinder permissionToken, boolean ignoreTargetSecurity, int userId); + boolean ignoreTargetSecurity, int userId); boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType, int userId); @@ -182,18 +182,6 @@ interface IActivityTaskManager { int addAppTask(in IBinder activityToken, in Intent intent, in ActivityManager.TaskDescription description, in Bitmap thumbnail); Point getAppTaskThumbnailSize(); - /** - * Only callable from the system. This token grants a temporary permission to call - * #startActivityAsCaller. The token will time out after START_AS_CALLER_TOKEN_TIMEOUT - * if it is not used. - * - * @param componentName The component name of the delegated component that is allowed to - * call #startActivityAsCaller with the returned token. - * - * @return Returns a token that can be given to a "delegate" app that may call - * #startActivityAsCaller - */ - IBinder requestStartActivityPermissionToken(in ComponentName componentName); oneway void releaseSomeActivities(in IApplicationThread app); Bitmap getTaskDescriptionIcon(in String filename, int userId); diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index ac979c495cf3..995a9f31b341 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -381,6 +381,10 @@ public class Instrumentation { * Force the global system in or out of touch mode. This can be used if your * instrumentation relies on the UI being in one more or the other when it starts. * + * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method + * will only take effect if the instrumentation was sourced from a process with + * {@code MODIFY_TOUCH_MODE_STATE} internal permission granted (shell already have it). + * * @param inTouch Set to true to be in touch mode, false to be in focus mode. */ public void setInTouchMode(boolean inTouch) { @@ -1995,7 +1999,7 @@ public class Instrumentation { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public ActivityResult execStartActivityAsCaller( Context who, IBinder contextThread, IBinder token, Activity target, - Intent intent, int requestCode, Bundle options, IBinder permissionToken, + Intent intent, int requestCode, Bundle options, boolean ignoreTargetSecurity, int userId) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { @@ -2030,7 +2034,7 @@ public class Instrumentation { .startActivityAsCaller(whoThread, who.getOpPackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, - requestCode, 0, null, options, permissionToken, + requestCode, 0, null, options, ignoreTargetSecurity, userId); checkStartActivityResult(result, intent); } catch (RemoteException e) { diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index f523a7d29713..83fe29fa2ba6 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -19,7 +19,6 @@ package android.app; import android.app.ActivityManager.RunningTaskInfo; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; -import android.os.Binder; import android.os.Build; import android.os.RemoteException; import android.window.TaskSnapshot; @@ -32,10 +31,18 @@ import android.window.TaskSnapshot; */ public abstract class TaskStackListener extends ITaskStackListener.Stub { + /** Whether this listener and the callback dispatcher are in different processes. */ + private boolean mIsRemote = true; + @UnsupportedAppUsage public TaskStackListener() { } + /** Indicates that this listener lives in system server. */ + public void setIsLocal() { + mIsRemote = false; + } + @Override @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void onTaskStackChanged() throws RemoteException { @@ -154,8 +161,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { @Override @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) throws RemoteException { - if (Binder.getCallingPid() != android.os.Process.myPid() - && snapshot != null && snapshot.getHardwareBuffer() != null) { + if (mIsRemote && snapshot != null && snapshot.getHardwareBuffer() != null) { // Preemptively clear any reference to the buffer snapshot.getHardwareBuffer().close(); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 82e5ebf755c2..df6627cffd0a 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6197,7 +6197,7 @@ public class DevicePolicyManager { * organization-owned managed profile. * * <p>The caller must hold the - * {@link android.Manifest.permission#SEND_LOST_MODE_LOCATION_UPDATES} permission. + * {@link android.Manifest.permission#TRIGGER_LOST_MODE} permission. * * <p> Not for use by third-party applications. * @@ -6207,7 +6207,7 @@ public class DevicePolicyManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) + @RequiresPermission(android.Manifest.permission.TRIGGER_LOST_MODE) public void sendLostModeLocationUpdate(@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) { throwIfParentInstance("sendLostModeLocationUpdate"); diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java index 2b3780e5a32b..ea30ef704bce 100644 --- a/core/java/android/app/admin/DevicePolicyResources.java +++ b/core/java/android/app/admin/DevicePolicyResources.java @@ -1741,26 +1741,14 @@ public final class DevicePolicyResources { /** * Class containing the identifiers used to update device management-related system strings - * in the Permissions module. + * for the permission settings. */ - public static final class PermissionController { - - private PermissionController() { + public static final class PermissionSettings { + + private PermissionSettings() { } - private static final String PREFIX = "PermissionController."; - - /** - * Title for settings page to show default apps for work. - */ - public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = - PREFIX + "WORK_PROFILE_DEFAULT_APPS_TITLE"; - - /** - * Summary indicating that a home role holder app is missing work profile support. - */ - public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE = - PREFIX + "HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE"; + private static final String PREFIX = "PermissionSettings."; /** * Summary of a permission switch in Settings when the background access is denied by an @@ -1790,5 +1778,29 @@ public final class DevicePolicyResources { public static final String LOCATION_AUTO_GRANTED_MESSAGE = PREFIX + "LOCATION_AUTO_GRANTED_MESSAGE"; } + + /** + * Class containing the identifiers used to update device management-related system strings + * for the default app settings. + */ + public static final class DefaultAppSettings { + + private DefaultAppSettings() { + } + + private static final String PREFIX = "DefaultAppSettings."; + + /** + * Title for settings page to show default apps for work. + */ + public static final String WORK_PROFILE_DEFAULT_APPS_TITLE = + PREFIX + "WORK_PROFILE_DEFAULT_APPS_TITLE"; + + /** + * Summary indicating that a home role holder app is missing work profile support. + */ + public static final String HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE = + PREFIX + "HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE"; + } } } diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index a1983ca9ee96..914b321b7506 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -469,6 +469,10 @@ public final class VirtualDeviceManager { /** * Called when the top activity is changed. * + * <p>Note: When there are no activities running on the virtual display, the + * {@link #onDisplayEmpty(int)} will be called. If the value topActivity is cached, it + * should be cleared when {@link #onDisplayEmpty(int)} is called. + * * @param displayId The display ID on which the activity change happened. * @param topActivity The component name of the top activity. */ diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 450e09a307bf..236c24475844 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -419,8 +419,8 @@ public class PackageInstaller { public @interface FileLocation{} /** - * The installer did not call SessionParams#setPackageSource(int) to specify the package - * source. + * The installer did not call {@link PackageInstaller.SessionParams#setPackageSource(int)} to + * specify the package source. */ public static final int PACKAGE_SOURCE_UNSPECIFIED = 0; @@ -444,8 +444,8 @@ public class PackageInstaller { /** * Code indicating that the package being installed comes from a file that was downloaded to - * the device by the user. For use in place of PACKAGE_SOURCE_LOCAL_FILE when the installer - * knows the package was downloaded. + * the device by the user. For use in place of {@link #PACKAGE_SOURCE_LOCAL_FILE} when the + * installer knows the package was downloaded. */ public static final int PACKAGE_SOURCE_DOWNLOADED_FILE = 4; @@ -1984,7 +1984,13 @@ public class PackageInstaller { } /** - * Sets the apk package installation source. + * Optionally indicate the package source of the app being installed. This is + * informational and may be used as a signal by the system. + * + * An installer should specify {@link #PACKAGE_SOURCE_OTHER} if no other package source + * constant adequately reflects the source for this session. + * + * The default value is {@link #PACKAGE_SOURCE_UNSPECIFIED}. */ public void setPackageSource(@PackageSourceType int packageSource) { this.packageSource = packageSource; @@ -2302,8 +2308,14 @@ public class PackageInstaller { * * <ul> * <li>{@code requireUserAction} is set to {@link #USER_ACTION_NOT_REQUIRED}.</li> - * <li>The app being installed targets {@link android.os.Build.VERSION_CODES#Q API 29} - * or higher.</li> + * <li>The app being installed targets: + * <ul> + * <li>{@link android.os.Build.VERSION_CODES#Q API 29} or higher on + * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li> + * <li>{@link android.os.Build.VERSION_CODES#R API 30} or higher after + * Android S ({@link android.os.Build.VERSION_CODES#S API 31})</li> + * </ul> + * </li> * <li>The installer is the {@link InstallSourceInfo#getInstallingPackageName() * installer of record} of an existing version of the app (in other words, this install * session is an app update) or the installer is updating itself.</li> @@ -2991,7 +3003,8 @@ public class PackageInstaller { } /** - * Gets the apk package installation source. + * Get the package source that was set in + * {@link PackageInstaller.SessionParams#setPackageSource(int)}. */ public @PackageSourceType int getPackageSource() { return packageSource; diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 56d092d8319d..52774e354c90 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -2241,10 +2241,20 @@ public final class ShortcutInfo implements Parcelable { } /** - * Return true if the shortcut is included in specified surface. + * Return true if the shortcut is excluded from specified surface. */ - public boolean isIncludedIn(@Surface int surface) { - return (mExcludedSurfaces & surface) == 0; + public boolean isExcludedFromSurfaces(@Surface int surface) { + return (mExcludedSurfaces & surface) != 0; + } + + /** + * Returns a bitmask of all surfaces this shortcut is excluded from. + * + * @see ShortcutInfo.Builder#setExcludedFromSurfaces(int) + */ + @Surface + public int getExcludedFromSurfaces() { + return mExcludedSurfaces; } /** @@ -2543,7 +2553,7 @@ public final class ShortcutInfo implements Parcelable { if (isLongLived()) { sb.append("Liv"); } - if (!isIncludedIn(SURFACE_LAUNCHER)) { + if (isExcludedFromSurfaces(SURFACE_LAUNCHER)) { sb.append("Hid-L"); } sb.append("]"); diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java index 0cb69a4da50f..61fd0416e3b2 100644 --- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java +++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java @@ -167,10 +167,7 @@ public final class WrappedApplicationKey implements Parcelable { protected WrappedApplicationKey(Parcel in) { mAlias = in.readString(); mEncryptedKeyMaterial = in.createByteArray(); - // Check if there is still data to be read. - if (in.dataAvail() > 0) { - mMetadata = in.createByteArray(); - } + mMetadata = in.createByteArray(); } @Override diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index b701e07e22e6..e9f099accac1 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -876,7 +876,7 @@ public final class Dataset implements Parcelable { * if (filter != null) { * fieldBuilder.setFilter(filter); * } - * Presentations.Builder presentationsBuilder = new Presentations.Builder(id); + * Presentations.Builder presentationsBuilder = new Presentations.Builder(); * if (presentation != null) { * presentationsBuilder.setMenuPresentation(presentation); * } diff --git a/core/java/android/service/autofill/Field.java b/core/java/android/service/autofill/Field.java index 8c905a6faa0d..d63cf337403b 100644 --- a/core/java/android/service/autofill/Field.java +++ b/core/java/android/service/autofill/Field.java @@ -18,7 +18,6 @@ package android.service.autofill; import android.annotation.NonNull; import android.annotation.Nullable; -import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import com.android.internal.util.DataClass; @@ -26,10 +25,9 @@ import com.android.internal.util.DataClass; import java.util.regex.Pattern; /** - * This class is used to set all information of a field. Such as the - * {@link AutofillId} of the field, the {@link AutofillValue} to be autofilled, - * a <a href="#Filtering">explicit filter</a>, and presentations to be visualized, - * etc. + * This class is used to set all information of a field. Such as the {@link AutofillValue} + * to be autofilled, a <a href="#Filtering">explicit filter</a>, and presentations to be + * visualized, etc. */ public final class Field { diff --git a/core/java/android/service/games/GameSessionTrampolineActivity.java b/core/java/android/service/games/GameSessionTrampolineActivity.java index ddea098680ea..3d97d0f59b33 100644 --- a/core/java/android/service/games/GameSessionTrampolineActivity.java +++ b/core/java/android/service/games/GameSessionTrampolineActivity.java @@ -51,7 +51,6 @@ public final class GameSessionTrampolineActivity extends Activity { startActivityAsCaller( getIntent().getParcelableExtra(INTENT_KEY), getIntent().getBundleExtra(OPTIONS_KEY), - null, false, getUserId(), REQUEST_CODE); diff --git a/core/java/android/service/trust/GrantTrustResult.java b/core/java/android/service/trust/GrantTrustResult.java index 7cf708a3d6e3..5b06bb8fbd07 100644 --- a/core/java/android/service/trust/GrantTrustResult.java +++ b/core/java/android/service/trust/GrantTrustResult.java @@ -32,7 +32,7 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ -@DataClass(genHiddenConstructor = true) +@DataClass @SystemApi public final class GrantTrustResult implements Parcelable { @@ -42,15 +42,10 @@ public final class GrantTrustResult implements Parcelable { /** The device went from locked to unlocked as a result of the call. */ public static final int STATUS_UNLOCKED_BY_GRANT = 1; + /** The status code of the result. */ @Status private int mStatus; - /** Returns a new {@link GrantTrustResult} with the specified status. */ - @NonNull - public static GrantTrustResult withStatus(@Status int status) { - return new GrantTrustResult(status); - } - // Code below generated by codegen v1.0.23. @@ -90,7 +85,8 @@ public final class GrantTrustResult implements Parcelable { /** * Creates a new GrantTrustResult. * - * @hide + * @param status + * The status code of the result. */ @DataClass.Generated.Member public GrantTrustResult( @@ -109,6 +105,9 @@ public final class GrantTrustResult implements Parcelable { // onConstructed(); // You can define this method to get a callback } + /** + * The status code of the result. + */ @DataClass.Generated.Member public @Status int getStatus() { return mStatus; @@ -165,10 +164,10 @@ public final class GrantTrustResult implements Parcelable { }; @DataClass.Generated( - time = 1647878197834L, + time = 1648138312806L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/service/trust/GrantTrustResult.java", - inputSignatures = "public static final int STATUS_UNKNOWN\npublic static final int STATUS_UNLOCKED_BY_GRANT\nprivate @android.service.trust.GrantTrustResult.Status int mStatus\npublic static @android.annotation.NonNull android.service.trust.GrantTrustResult withStatus(int)\nclass GrantTrustResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)") + inputSignatures = "public static final int STATUS_UNKNOWN\npublic static final int STATUS_UNLOCKED_BY_GRANT\nprivate @android.service.trust.GrantTrustResult.Status int mStatus\nclass GrantTrustResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass") @Deprecated private void __metadata() {} diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index f8445921d3b0..a3696e398668 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -38,7 +38,6 @@ import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.SrvccState; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; -import android.telephony.TelephonyManager.CarrierPrivilegesListener; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.util.ArraySet; @@ -1264,149 +1263,52 @@ public class TelephonyRegistryManager { pkgName, attributionTag, callback, new int[0], notifyNow); } - // TODO(b/216549778): Remove listener logic once all clients switch to CarrierPrivilegesCallback private static class CarrierPrivilegesCallbackWrapper extends ICarrierPrivilegesCallback.Stub implements ListenerExecutor { - // Either mListener or mCallback may be null, never both - @Nullable private final WeakReference<CarrierPrivilegesListener> mListener; - @Nullable private final WeakReference<CarrierPrivilegesCallback> mCallback; + @NonNull private final WeakReference<CarrierPrivilegesCallback> mCallback; @NonNull private final Executor mExecutor; CarrierPrivilegesCallbackWrapper( @NonNull CarrierPrivilegesCallback callback, @NonNull Executor executor) { - mListener = null; mCallback = new WeakReference<>(callback); mExecutor = executor; } - CarrierPrivilegesCallbackWrapper( - @NonNull CarrierPrivilegesListener listener, @NonNull Executor executor) { - mListener = new WeakReference<>(listener); - mCallback = null; - mExecutor = executor; - } - @Override public void onCarrierPrivilegesChanged( @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids) { - if (mListener != null) { - Binder.withCleanCallingIdentity( - () -> - executeSafely( - mExecutor, - mListener::get, - cpl -> - cpl.onCarrierPrivilegesChanged( - privilegedPackageNames, privilegedUids))); - } - - if (mCallback != null) { - // AIDL interface does not support Set, keep the List/Array and translate them here - Set<String> privilegedPkgNamesSet = Set.copyOf(privilegedPackageNames); - Set<Integer> privilegedUidsSet = Arrays.stream(privilegedUids).boxed().collect( - Collectors.toSet()); - Binder.withCleanCallingIdentity( - () -> - executeSafely( - mExecutor, - mCallback::get, - cpc -> - cpc.onCarrierPrivilegesChanged( - privilegedPkgNamesSet, privilegedUidsSet))); - } + // AIDL interface does not support Set, keep the List/Array and translate them here + Set<String> privilegedPkgNamesSet = Set.copyOf(privilegedPackageNames); + Set<Integer> privilegedUidsSet = Arrays.stream(privilegedUids).boxed().collect( + Collectors.toSet()); + Binder.withCleanCallingIdentity( + () -> + executeSafely( + mExecutor, + mCallback::get, + cpc -> + cpc.onCarrierPrivilegesChanged( + privilegedPkgNamesSet, privilegedUidsSet))); } @Override public void onCarrierServiceChanged(@Nullable String packageName, int uid) { - if (mCallback != null) { - Binder.withCleanCallingIdentity( - () -> - executeSafely( - mExecutor, - mCallback::get, - cpc -> cpc.onCarrierServiceChanged(packageName, uid))); - } + Binder.withCleanCallingIdentity( + () -> + executeSafely( + mExecutor, + mCallback::get, + cpc -> cpc.onCarrierServiceChanged(packageName, uid))); } } - // TODO(b/216549778): Change the map key to CarrierPrivilegesCallback once all clients switch to - // CarrierPrivilegesCallback. Before that, the key is either CarrierPrivilegesCallback or - // CarrierPrivilegesListener, no logic actually depends on the type. @NonNull @GuardedBy("sCarrierPrivilegeCallbacks") - private static final WeakHashMap<Object, WeakReference<CarrierPrivilegesCallbackWrapper>> + private static final WeakHashMap<CarrierPrivilegesCallback, + WeakReference<CarrierPrivilegesCallbackWrapper>> sCarrierPrivilegeCallbacks = new WeakHashMap<>(); /** - * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to - * receive callbacks when the set of packages with carrier privileges changes. The callback will - * immediately be called with the latest state. - * - * @param logicalSlotIndex The SIM slot to listen on - * @param executor The executor where {@code listener} will be invoked - * @param listener The callback to register - * - * @deprecated Use {@link #addCarrierPrivilegesCallback} instead. This API will be removed - * prior to API finalization. - */ - @Deprecated - public void addCarrierPrivilegesListener( - int logicalSlotIndex, - @NonNull @CallbackExecutor Executor executor, - @NonNull CarrierPrivilegesListener listener) { - if (listener == null || executor == null) { - throw new IllegalArgumentException("listener and executor must be non-null"); - } - synchronized (sCarrierPrivilegeCallbacks) { - WeakReference<CarrierPrivilegesCallbackWrapper> existing = - sCarrierPrivilegeCallbacks.get(listener); - if (existing != null && existing.get() != null) { - Log.d(TAG, "addCarrierPrivilegesListener: listener already registered"); - return; - } - CarrierPrivilegesCallbackWrapper wrapper = - new CarrierPrivilegesCallbackWrapper(listener, executor); - sCarrierPrivilegeCallbacks.put(listener, new WeakReference<>(wrapper)); - try { - sRegistry.addCarrierPrivilegesCallback( - logicalSlotIndex, - wrapper, - mContext.getOpPackageName(), - mContext.getAttributionTag()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } - - /** - * Unregisters a {@link CarrierPrivilegesListener}. - * - * @param listener The callback to unregister - * - * @deprecated Use {@link #removeCarrierPrivilegesCallback} instead. The callback will prior - * to API finalization. - */ - @Deprecated - public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must be non-null"); - } - synchronized (sCarrierPrivilegeCallbacks) { - WeakReference<CarrierPrivilegesCallbackWrapper> ref = - sCarrierPrivilegeCallbacks.remove(listener); - if (ref == null) return; - CarrierPrivilegesCallbackWrapper wrapper = ref.get(); - if (wrapper == null) return; - try { - sRegistry.removeCarrierPrivilegesCallback(wrapper, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } - - /** * Registers a {@link CarrierPrivilegesCallback} on the given {@code logicalSlotIndex} to * receive callbacks when the set of packages with carrier privileges changes. The callback will * immediately be called with the latest state. diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index a13579d0acad..406281d4cade 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -401,7 +401,7 @@ public class SurfaceControlViewHost { public void relayout(WindowManager.LayoutParams attrs, WindowlessWindowManager.ResizeCompleteCallback callback) { mViewRoot.setLayoutParams(attrs, false); - mViewRoot.setReportNextDraw(); + mViewRoot.setReportNextDraw(true /* syncBuffer */); mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback); } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 413855639d09..c04b0964a7a4 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -50,6 +50,7 @@ import android.view.accessibility.IAccessibilityEmbeddedConnection; import com.android.internal.view.SurfaceCallbackHelper; import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; @@ -203,8 +204,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private int mSurfaceFlags = SurfaceControl.HIDDEN; - private int mPendingReportDraws; - /** * Transaction that should be used from the render thread. This transaction is only thread safe * with other calls directly from the render thread. @@ -212,11 +211,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private final SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction(); /** - * Used on the main thread to set the transaction that will be synced with the main window. - */ - private final Transaction mSyncTransaction = new Transaction(); - - /** * Transaction that should be used whe * {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All * frame callbacks can use the same transaction since they will be thread safe @@ -391,31 +385,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } - private void performDrawFinished(@Nullable Transaction t) { - if (t != null) { - mSyncTransaction.merge(t); - } - - if (mPendingReportDraws > 0) { - mDrawFinished = true; - if (mAttachedToWindow) { - mParent.requestTransparentRegion(SurfaceView.this); - notifyDrawFinished(); - invalidate(); - } - } else { - Log.e(TAG, System.identityHashCode(this) + "finished drawing" - + " but no pending report draw (extra call" - + " to draw completion runnable?)"); - } - } - - void notifyDrawFinished() { - ViewRootImpl viewRoot = getViewRootImpl(); - if (viewRoot != null) { - viewRoot.pendingDrawFinished(mSyncTransaction); + private void performDrawFinished() { + mDrawFinished = true; + if (mAttachedToWindow) { + mParent.requestTransparentRegion(SurfaceView.this); + invalidate(); } - mPendingReportDraws--; } @Override @@ -438,10 +413,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mGlobalListenersAdded = false; } - while (mPendingReportDraws > 0) { - notifyDrawFinished(); - } - mRequestedVisible = false; updateSurface(); @@ -993,10 +964,17 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return; } - final boolean realSizeChanged = performSurfaceTransaction(viewRoot, - translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction); final boolean redrawNeeded = sizeChanged || creating || hintChanged || (mVisible && !mDrawFinished); + final TransactionCallback transactionCallback = + redrawNeeded ? new TransactionCallback() : null; + if (redrawNeeded && viewRoot.wasRelayoutRequested() && viewRoot.isInSync()) { + mBlastBufferQueue.syncNextTransaction( + false /* acquireSingleBuffer */, + transactionCallback::onTransactionReady); + } + final boolean realSizeChanged = performSurfaceTransaction(viewRoot, + translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction); try { SurfaceHolder.Callback[] callbacks = null; @@ -1015,9 +993,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mIsCreating = true; if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "visibleChanged -- surfaceCreated"); - if (callbacks == null) { - callbacks = getSurfaceCallbacks(); - } + callbacks = getSurfaceCallbacks(); for (SurfaceHolder.Callback c : callbacks) { c.surfaceCreated(mSurfaceHolder); } @@ -1035,32 +1011,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } if (redrawNeeded) { - if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " - + "surfaceRedrawNeeded"); - if (callbacks == null) { - callbacks = getSurfaceCallbacks(); - } - - final boolean wasRelayoutRequested = viewRoot.wasRelayoutRequested(); - if (wasRelayoutRequested && (mBlastBufferQueue != null)) { - mBlastBufferQueue.syncNextTransaction( - false /* acquireSingleBuffer */, - this::onDrawFinished); - } - mPendingReportDraws++; - viewRoot.drawPending(); - SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> { - if (mBlastBufferQueue != null) { - mBlastBufferQueue.stopContinuousSyncTransaction(); - } - // If relayout was requested, then a callback from BBQ will - // be invoked with the sync transaction. onDrawFinished will be - // called in there - if (!wasRelayoutRequested) { - onDrawFinished(null); - } - }); - sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); + redrawNeeded(callbacks, transactionCallback); } } } finally { @@ -1079,6 +1030,64 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } + private void redrawNeeded(SurfaceHolder.Callback[] callbacks, + @Nullable TransactionCallback transactionCallback) { + if (DEBUG) { + Log.i(TAG, System.identityHashCode(this) + " surfaceRedrawNeeded"); + } + final SurfaceHolder.Callback[] capturedCallbacks = + callbacks == null ? getSurfaceCallbacks() : callbacks; + + ViewRootImpl viewRoot = getViewRootImpl(); + boolean isVriSync = viewRoot.addToSync(syncBufferCallback -> + redrawNeededAsync(capturedCallbacks, () -> { + if (mBlastBufferQueue != null) { + mBlastBufferQueue.stopContinuousSyncTransaction(); + } + + Transaction t = null; + if (transactionCallback != null && mBlastBufferQueue != null) { + t = transactionCallback.waitForTransaction(); + } + // If relayout was requested, then a callback from BBQ will + // be invoked with the sync transaction. onDrawFinished will be + // called in there + syncBufferCallback.onBufferReady(t); + onDrawFinished(); + })); + + // If isVriSync, then everything was setup in the addToSync. + if (isVriSync) { + return; + } + + redrawNeededAsync(capturedCallbacks, this::onDrawFinished); + } + + private void redrawNeededAsync(SurfaceHolder.Callback[] callbacks, + Runnable callbacksCollected) { + SurfaceCallbackHelper sch = new SurfaceCallbackHelper(callbacksCollected); + sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); + } + + private static class TransactionCallback { + private final CountDownLatch mCountDownLatch = new CountDownLatch(1); + private Transaction mTransaction; + + Transaction waitForTransaction() { + try { + mCountDownLatch.await(); + } catch (InterruptedException e) { + } + return mTransaction; + } + + void onTransactionReady(Transaction t) { + mTransaction = t; + mCountDownLatch.countDown(); + } + } + /** * Copy the Surface from the SurfaceControl or the blast adapter. * @@ -1189,13 +1198,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat); } - private void onDrawFinished(@Nullable Transaction t) { + private void onDrawFinished() { if (DEBUG) { Log.i(TAG, System.identityHashCode(this) + " " + "finishedDrawing"); } - runOnUiThread(() -> performDrawFinished(t)); + runOnUiThread(this::performDrawFinished); } /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2613c1a2992f..fa3834d21036 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -587,11 +587,16 @@ public final class ViewRootImpl implements ViewParent, boolean mReportNextDraw; + /** - * Set whether the draw should use blast sync. This is in case the draw is canceled, - * but will be rescheduled. We still want the next draw to be sync. + * Set whether the draw should send the buffer to system server. When set to true, VRI will + * create a sync transaction with BBQ and send the resulting buffer to system server. If false, + * VRI will not try to sync a buffer in BBQ, but still report when a draw occurred. */ - boolean mNextDrawUseBlastSync; + private boolean mSyncBuffer = false; + + int mSyncSeqId = 0; + int mLastSyncSeqId = 0; boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; @@ -812,6 +817,10 @@ public final class ViewRootImpl implements ViewParent, return mHandwritingInitiator; } + private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer(); + private int mLastSyncId = -1; + private SurfaceSyncer.SyncBufferCallback mSyncBufferCallback; + /** * Keeps track of the last frame number that was attempted to draw. Should only be accessed on * the RenderThread. @@ -849,8 +858,6 @@ public final class ViewRootImpl implements ViewParent, * integer back over relayout. */ private Bundle mRelayoutBundle = new Bundle(); - private int mSyncSeqId = 0; - private int mLastSyncSeqId = 0; private String mTag = TAG; @@ -2331,10 +2338,9 @@ public final class ViewRootImpl implements ViewParent, final int systemUiFlag = publicType == Type.statusBars() ? View.SYSTEM_UI_FLAG_FULLSCREEN : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; - final boolean wasVisible = (info.globalVisibility & systemUiFlag) == 0; if (visible) { info.globalVisibility &= ~systemUiFlag; - if (!wasVisible && hasControl) { + if (hasControl && (mAttachInfo.mSystemUiVisibility & systemUiFlag) != 0) { // The local system UI visibility can only be cleared while we have the control. info.localChanges |= systemUiFlag; } @@ -2654,7 +2660,6 @@ public final class ViewRootImpl implements ViewParent, private void performTraversals() { // cache mView since it is used so much below... final View host = mView; - if (DBG) { System.out.println("======================================"); System.out.println("performTraversals"); @@ -2899,8 +2904,6 @@ public final class ViewRootImpl implements ViewParent, mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance); } } - final boolean wasReportNextDraw = mReportNextDraw; - boolean useBlastSync = mNextDrawUseBlastSync; if (mFirst || windowShouldResize || viewVisibilityChanged || params != null || mForceNextWindowRelayout) { @@ -2939,9 +2942,7 @@ public final class ViewRootImpl implements ViewParent, Log.d(mTag, "Relayout called with blastSync"); } reportNextDraw(); - if (isHardwareEnabled()) { - useBlastSync = true; - } + mSyncBuffer = true; } final boolean surfaceControlChanged = @@ -3177,7 +3178,7 @@ public final class ViewRootImpl implements ViewParent, // done to achieve a more hermetic fix for S, but it's entirely // possible that checking the most recent value is actually more // correct here. - if (!mStopped || wasReportNextDraw) { + if (!mStopped || mReportNextDraw) { if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() || dispatchApplyInsets || updatedConfiguration) { int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width, @@ -3246,7 +3247,7 @@ public final class ViewRootImpl implements ViewParent, prepareSurfaces(); } - final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw); + final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); boolean triggerGlobalLayoutListener = didLayout || mAttachInfo.mRecomputeGlobalAttributes; if (didLayout) { @@ -3439,51 +3440,37 @@ public final class ViewRootImpl implements ViewParent, mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes); - // Remember if we must report the next draw. if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { reportNextDraw(); } - boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; - if (mBLASTDrawConsumer != null) { - useBlastSync = true; + boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw(); + if (!cancelAndRedraw) { + createSyncIfNeeded(); } - if (!cancelDraw) { + if (!isViewVisible) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { for (int i = 0; i < mPendingTransitions.size(); ++i) { - mPendingTransitions.get(i).startChangingAnimations(); + mPendingTransitions.get(i).endChangingAnimations(); } mPendingTransitions.clear(); } - performDraw(useBlastSync); - mNextDrawUseBlastSync = false; - } else { - if (isViewVisible) { - // Try again - mNextDrawUseBlastSync = useBlastSync; - scheduleTraversals(); - } else { - if (mPendingTransitions != null && mPendingTransitions.size() > 0) { - for (int i = 0; i < mPendingTransitions.size(); ++i) { - mPendingTransitions.get(i).endChangingAnimations(); - } - mPendingTransitions.clear(); - } - - // We may never draw since it's not visible. Report back that we're finished - // drawing. - if (!wasReportNextDraw && mReportNextDraw) { - mReportNextDraw = false; - pendingDrawFinished(); - } - // Make sure the consumer is not waiting if the view root was just made invisible. - if (mBLASTDrawConsumer != null) { - mBLASTDrawConsumer.accept(null); - mBLASTDrawConsumer = null; + if (mSyncBufferCallback != null) { + mSyncBufferCallback.onBufferReady(null); + } + } else if (cancelAndRedraw) { + // Try again + scheduleTraversals(); + } else { + if (mPendingTransitions != null && mPendingTransitions.size() > 0) { + for (int i = 0; i < mPendingTransitions.size(); ++i) { + mPendingTransitions.get(i).startChangingAnimations(); } + mPendingTransitions.clear(); } + performDraw(); } if (mAttachInfo.mContentCaptureEvents != null) { @@ -3492,6 +3479,48 @@ public final class ViewRootImpl implements ViewParent, mIsInTraversal = false; mRelayoutRequested = false; + + if (!cancelAndRedraw) { + mReportNextDraw = false; + mSyncBufferCallback = null; + mSyncBuffer = false; + if (mLastSyncId != -1) { + mSurfaceSyncer.markSyncReady(mLastSyncId); + mLastSyncId = -1; + } + } + } + + private void createSyncIfNeeded() { + // Started a sync already. + if (mLastSyncId != -1) { + return; + } + + Consumer<Transaction> syncConsumer = null; + final int seqId = mSyncSeqId; + + if (mBLASTDrawConsumer != null) { + syncConsumer = mBLASTDrawConsumer; + mBLASTDrawConsumer = null; + } else if (mReportNextDraw) { + syncConsumer = transaction -> { + mSurfaceChangedTransaction.merge(transaction); + reportDrawFinished(seqId); + }; + } + + if (syncConsumer != null) { + final Consumer<Transaction> capturedSyncConsumer = syncConsumer; + mLastSyncId = mSurfaceSyncer.setupSync(transaction -> { + // Callback will be invoked on executor thread so post to main thread. + mHandler.postAtFrontOfQueue(() -> capturedSyncConsumer.accept(transaction)); + }); + if (DEBUG_BLAST) { + Log.d(mTag, "Setup new sync id=" + mLastSyncId); + } + mSurfaceSyncer.addToSync(mLastSyncId, mSyncTarget); + } } private void notifyContentCatpureEvents() { @@ -4105,57 +4134,13 @@ public final class ViewRootImpl implements ViewParent, } } - /** - * A count of the number of calls to pendingDrawFinished we - * require to notify the WM drawing is complete. - */ - int mDrawsNeededToReport = 0; - - /** - * Delay notifying WM of draw finished until - * a balanced call to pendingDrawFinished. - */ - void drawPending() { - mDrawsNeededToReport++; - } - - void pendingDrawFinished(Transaction t) { - if (mDrawsNeededToReport == 0) { - throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls"); - } - - if (t != null) { - if (DEBUG_BLAST) { - Log.d(mTag, "Merging transaction into main window transaction"); - } - mSurfaceChangedTransaction.merge(t); - } - - mDrawsNeededToReport--; - if (mDrawsNeededToReport == 0) { - reportDrawFinished(); - } else if (DEBUG_BLAST) { - Log.d(mTag, "pendingDrawFinished. Waiting on draw reported mDrawsNeededToReport=" - + mDrawsNeededToReport); - } - } - - void pendingDrawFinished() { - pendingDrawFinished(null); - } - - private void postDrawFinished() { - mHandler.sendEmptyMessage(MSG_DRAW_FINISHED); - } - - private void reportDrawFinished() { + private void reportDrawFinished(int seqId) { if (DEBUG_BLAST) { - Log.d(mTag, "reportDrawFinished"); + Log.d(mTag, "reportDrawFinished " + Debug.getCallers(5)); } - mDrawsNeededToReport = 0; try { - mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE); + mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, seqId); } catch (RemoteException e) { Log.e(mTag, "Unable to report draw finished", e); mSurfaceChangedTransaction.apply(); @@ -4171,6 +4156,19 @@ public final class ViewRootImpl implements ViewParent, return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); } + boolean addToSync(SurfaceSyncer.SyncTarget syncable) { + if (mLastSyncId == -1) { + return false; + } + mSurfaceSyncer.addToSync(mLastSyncId, syncable); + return true; + } + + + public boolean isInSync() { + return mLastSyncId != -1; + } + private void addFrameCommitCallbackIfNeeded() { if (!isHardwareEnabled()) { return; @@ -4201,188 +4199,82 @@ public final class ViewRootImpl implements ViewParent, }); } - private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync( - boolean useBlastSync, boolean reportNextDraw, Consumer<Transaction> blastSyncConsumer) { - return didProduceBuffer -> { - if (DEBUG_BLAST) { - Log.d(mTag, "Received frameCommittedCallback " - + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum - + " didProduceBuffer=" + didProduceBuffer); - } - - // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next - // draw attempt. The next transaction and transaction complete callback were only set - // for the current draw attempt. - final Transaction pendingTransactions; - if (!didProduceBuffer) { - mBlastBufferQueue.syncNextTransaction(null); - // Get the transactions that were sent to mergeWithNextTransaction since the - // frame didn't draw on this vsync. It's possible the frame will draw later, but - // it's better to not be sync than to block on a frame that may never come. - pendingTransactions = mBlastBufferQueue.gatherPendingTransactions( - mRtLastAttemptedDrawFrameNum); - if (!useBlastSync && !reportNextDraw) { - pendingTransactions.apply(); - } - } else { - pendingTransactions = null; - } - // Post at front of queue so the buffer can be processed immediately and allow RT - // to continue processing new buffers. If RT tries to process buffers before the sync - // buffer is applied, the new buffers will not get acquired and could result in a - // deadlock. UI thread would wait on RT, but RT would be blocked waiting for a free - // buffer. - mHandler.postAtFrontOfQueue(() -> { - if (!didProduceBuffer && useBlastSync) { - mSurfaceChangedTransaction.merge(pendingTransactions); - if (blastSyncConsumer != null) { - blastSyncConsumer.accept(mSurfaceChangedTransaction); - } - } - - // This is to ensure pendingDrawFinished is only called exactly one time per draw - // attempt when reportNextDraw is true. Since, we sometimes create a sync - // transaction callback, the callback will handle calling pendingDrawFinished. - // However, there are cases where the transaction callback may not be called. - // 1. If useBlastSync is false, then we know that a sync transaction callback was - // not created so we won't invoke pendingDrawFinished there. - // 2. If the draw didn't produce a frame, didProduceBuffer == false, then we know - // the sync transaction callback will not be invoked even if one was set up. - if (reportNextDraw && (!didProduceBuffer || !useBlastSync)) { - pendingDrawFinished(); - } - }); - - }; - } - @Nullable - private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync, - boolean reportNextDraw) { + private void registerFrameDrawingCallbackForBlur() { if (!isHardwareEnabled()) { - return null; + return; } final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates(); final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions(); - if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) { - return null; - } - - final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer; - mBLASTDrawConsumer = null; - - if (DEBUG_BLAST) { - Log.d(mTag, "Creating frameDrawingCallback" - + " nextDrawUseBlastSync=" + useBlastSync - + " reportNextDraw=" + reportNextDraw - + " hasBlurUpdates=" + hasBlurUpdates - + " hasBlastSyncConsumer=" + (blastSyncConsumer != null) - + " mHasPendingTransactions=" + mHasPendingTransactions); + if (!needsCallbackForBlur) { + return; } final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame = - needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null; - final boolean hasPendingTransactions = mHasPendingTransactions; - mHasPendingTransactions = false; + mBlurRegionAggregator.getBlurRegionsCopyForRT(); // The callback will run on the render thread. - return new FrameDrawingCallback() { - @Override - public void onFrameDraw(long frame) { - } + registerRtFrameCallback((frame) -> mBlurRegionAggregator + .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates)); + } + private void registerCallbackForPendingTransactions() { + registerRtFrameCallback(new FrameDrawingCallback() { @Override public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) { - if (DEBUG_BLAST) { - Log.d(mTag, - "Received frameDrawingCallback syncResult=" + syncResult + " frameNum=" - + frame + "."); - } - - mRtLastAttemptedDrawFrameNum = frame; - - if (needsCallbackForBlur) { - mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame, - blurRegionsForFrame, hasBlurUpdates); - } - - if (mBlastBufferQueue == null) { - return null; - } - - if (!useBlastSync && !reportNextDraw && !hasPendingTransactions) { - return null; - } - - // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or - // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up - // any blast sync or commit callback, and the code should directly call - // pendingDrawFinished. if ((syncResult & (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) { - if (reportNextDraw) { - mHandler.postAtFrontOfQueue(() -> pendingDrawFinished()); - } + mBlastBufferQueue.applyPendingTransactions(frame); return null; } - if (DEBUG_BLAST) { - Log.d(mTag, "Setting up sync and frameCommitCallback"); - } - - if (useBlastSync) { - // Frame callbacks will always occur after submitting draw requests and before - // the draw actually occurs. This will ensure that we set the next transaction - // for the frame that's about to get drawn and not on a previous frame. - mBlastBufferQueue.syncNextTransaction( - t -> { - mHandler.postAtFrontOfQueue(() -> { - mSurfaceChangedTransaction.merge(t); - if (blastSyncConsumer != null) { - blastSyncConsumer.accept(mSurfaceChangedTransaction); - } + return didProduceBuffer -> { + if (!didProduceBuffer) { + mBlastBufferQueue.applyPendingTransactions(frame); + } + }; - if (reportNextDraw) { - pendingDrawFinished(); - } - }); - }); - } + } - return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw, - blastSyncConsumer); + @Override + public void onFrameDraw(long frame) { } - }; + }); } - private void performDraw(boolean useBlastSync) { + private void performDraw() { if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { return; } else if (mView == null) { return; } - final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw || useBlastSync; + final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null; mFullRedrawNeeded = false; mIsDrawing = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); - FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync, - mReportNextDraw); - if (frameDrawingCallback != null) { - mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback); - } + registerFrameDrawingCallbackForBlur(); addFrameCommitCallbackIfNeeded(); - boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw); + + boolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null; + if (usingAsyncReport) { + registerCallbacksForSync(mSyncBuffer, mSyncBufferCallback); + } else if (mHasPendingTransactions) { + // These callbacks are only needed if there's no sync involved and there were calls to + // applyTransactionOnDraw. These callbacks check if the draw failed for any reason and + // apply those transactions directly so they don't get stuck forever. + registerCallbackForPendingTransactions(); + } + mHasPendingTransactions = false; try { boolean canUseAsync = draw(fullRedrawNeeded); if (usingAsyncReport && !canUseAsync) { mAttachInfo.mThreadedRenderer.setFrameCallback(null); usingAsyncReport = false; - mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback); } } finally { mIsDrawing = false; @@ -4400,7 +4292,6 @@ public final class ViewRootImpl implements ViewParent, } if (mReportNextDraw) { - mReportNextDraw = false; // if we're using multi-thread renderer, wait for the window frame draws if (mWindowDrawCountDown != null) { @@ -4421,7 +4312,11 @@ public final class ViewRootImpl implements ViewParent, } if (mSurfaceHolder != null && mSurface.isValid()) { - SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished); + final SurfaceSyncer.SyncBufferCallback syncBufferCallback = mSyncBufferCallback; + SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> + mHandler.post(() -> syncBufferCallback.onBufferReady(null))); + mSyncBufferCallback = null; + SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks); @@ -4429,9 +4324,11 @@ public final class ViewRootImpl implements ViewParent, if (mAttachInfo.mThreadedRenderer != null) { mAttachInfo.mThreadedRenderer.fence(); } - pendingDrawFinished(); } } + if (mSyncBufferCallback != null && !usingAsyncReport) { + mSyncBufferCallback.onBufferReady(null); + } if (mPerformContentCapture) { performContentCaptureInitialReport(); } @@ -5440,7 +5337,6 @@ public final class ViewRootImpl implements ViewParent, private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26; private static final int MSG_UPDATE_POINTER_ICON = 27; private static final int MSG_POINTER_CAPTURE_CHANGED = 28; - private static final int MSG_DRAW_FINISHED = 29; private static final int MSG_INSETS_CHANGED = 30; private static final int MSG_INSETS_CONTROL_CHANGED = 31; private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32; @@ -5503,8 +5399,6 @@ public final class ViewRootImpl implements ViewParent, return "MSG_UPDATE_POINTER_ICON"; case MSG_POINTER_CAPTURE_CHANGED: return "MSG_POINTER_CAPTURE_CHANGED"; - case MSG_DRAW_FINISHED: - return "MSG_DRAW_FINISHED"; case MSG_INSETS_CHANGED: return "MSG_INSETS_CHANGED"; case MSG_INSETS_CONTROL_CHANGED: @@ -5735,9 +5629,6 @@ public final class ViewRootImpl implements ViewParent, final boolean hasCapture = msg.arg1 != 0; handlePointerCaptureChanged(hasCapture); } break; - case MSG_DRAW_FINISHED: { - pendingDrawFinished(); - } break; case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: { systemGestureExclusionChanged(); } break; @@ -8066,7 +7957,6 @@ public final class ViewRootImpl implements ViewParent, private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending) throws RemoteException { - mRelayoutRequested = true; float appScale = mAttachInfo.mApplicationScale; boolean restore = false; @@ -8639,7 +8529,8 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void dispatchResized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, boolean forceLayout, - boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) { + boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) { + Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED); SomeArgs args = SomeArgs.obtain(); final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid()); @@ -8649,8 +8540,9 @@ public final class ViewRootImpl implements ViewParent, args.argi1 = forceLayout ? 1 : 0; args.argi2 = alwaysConsumeSystemBars ? 1 : 0; args.argi3 = displayId; - args.argi4 = seqId; + args.argi4 = syncSeqId; args.argi5 = resizeMode; + msg.obj = args; mHandler.sendMessage(msg); } @@ -9942,8 +9834,8 @@ public final class ViewRootImpl implements ViewParent, } private void reportNextDraw() { - if (mReportNextDraw == false) { - drawPending(); + if (DEBUG_BLAST) { + Log.d(mTag, "reportNextDraw " + Debug.getCallers(5)); } mReportNextDraw = true; } @@ -9954,9 +9846,14 @@ public final class ViewRootImpl implements ViewParent, * This method is only supposed to be used to speed up the interaction from SystemUI and window * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE * unless you fully understand this interaction. + * + * @param syncBuffer If true, the transaction that contains the buffer from the draw should be + * sent to system to be synced. If false, VRI will not try to sync the buffer, + * but only report back that a buffer was drawn. * @hide */ - public void setReportNextDraw() { + public void setReportNextDraw(boolean syncBuffer) { + mSyncBuffer = syncBuffer; reportNextDraw(); invalidate(); } @@ -10035,11 +9932,11 @@ public final class ViewRootImpl implements ViewParent, @Override public void resized(ClientWindowFrames frames, boolean reportDraw, MergedConfiguration mergedConfiguration, boolean forceLayout, - boolean alwaysConsumeSystemBars, int displayId, int seqId, int resizeMode) { + boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, int resizeMode) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout, - alwaysConsumeSystemBars, displayId, seqId, resizeMode); + alwaysConsumeSystemBars, displayId, syncSeqId, resizeMode); } } @@ -10982,14 +10879,15 @@ public final class ViewRootImpl implements ViewParent, return mWindowSession; } - private void registerCallbacksForSync( + private void registerCallbacksForSync(boolean syncBuffer, final SurfaceSyncer.SyncBufferCallback syncBufferCallback) { if (!isHardwareEnabled()) { - // TODO: correctly handle when hardware disabled - syncBufferCallback.onBufferReady(null); return; } + if (DEBUG_BLAST) { + Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer); + } mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { @@ -11018,7 +10916,9 @@ public final class ViewRootImpl implements ViewParent, Log.d(mTag, "Setting up sync and frameCommitCallback"); } - mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t)); + if (syncBuffer) { + mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady); + } return didProduceBuffer -> { if (DEBUG_BLAST) { @@ -11032,18 +10932,40 @@ public final class ViewRootImpl implements ViewParent, // were only set for the current draw attempt. if (!didProduceBuffer) { mBlastBufferQueue.syncNextTransaction(null); + // Gather the transactions that were sent to mergeWithNextTransaction // since the frame didn't draw on this vsync. It's possible the frame will // draw later, but it's better to not be sync than to block on a frame that // may never come. syncBufferCallback.onBufferReady( mBlastBufferQueue.gatherPendingTransactions(frame)); + return; + } + + // If we didn't request to sync a buffer, then we won't get the + // syncNextTransaction callback. Instead, just report back to the Syncer so it + // knows that this sync request is complete. + if (!syncBuffer) { + syncBufferCallback.onBufferReady(null); } }; } }); } - public final SurfaceSyncer.SyncTarget mSyncTarget = - syncBufferCallback -> registerCallbacksForSync(syncBufferCallback); + public final SurfaceSyncer.SyncTarget mSyncTarget = this::readyToSync; + + private void readyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) { + if (mSyncBufferCallback != null) { + Log.d(mTag, "Already set sync for the next draw."); + mSyncBufferCallback.onBufferReady(null); + } + if (DEBUG_BLAST) { + Log.d(mTag, "Setting syncFrameCallback"); + } + mSyncBufferCallback = syncBufferCallback; + if (!mIsInTraversal && !mTraversalScheduled) { + scheduleTraversals(); + } + } } diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index 9793f8cfc83b..4387701f7a24 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -171,8 +171,9 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { public void setSystemBarsAppearance(int appearance, int mask) { mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED; final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags; - if (insetsFlags.appearance != appearance) { - insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask); + final int newAppearance = (insetsFlags.appearance & ~mask) | (appearance & mask); + if (insetsFlags.appearance != newAppearance) { + insetsFlags.appearance = newAppearance; mViewRoot.mWindowAttributesChanged = true; mViewRoot.scheduleTraversals(); } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 07db91f31efc..6fa6d3964ad4 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -3077,11 +3077,26 @@ public final class AutofillManager { } /** - * Like {@link #showAutofillDialog(View)} but for virtual views. + * If autofill suggestions for a + * <a href="{@docRoot}reference/android/service/autofill/Dataset.html#FillDialogUI"> + * dialog-style UI</a> are available for virtual {@code view}, shows a dialog allowing the user + * to select a suggestion and returns {@code true}. + * <p> + * The dialog may not be shown if the autofill service does not support it, if the autofill + * request has not returned a response yet, if the dialog was shown previously, or if the + * input method is already shown. + * <p> + * It is recommended apps to call this method the first time a user focuses on + * an autofill-able form, and to avoid showing the input method if the dialog is shown. If + * this method returns {@code false}, you should then instead show the input method (assuming + * that is how the view normally handles the focus event). If the user re-focuses on the view, + * you should not call this method again so as to not disrupt usage of the input method. * - * @param virtualId id identifying the virtual child inside the parent view. + * @param view the view hosting the virtual view hierarchy which is used to show autofill + * suggestions. + * @param virtualId id identifying the virtual view inside the host view. + * @return {@code true} if the autofill dialog is being shown */ - // TODO(b/210926084): Consider whether to include the one-time show logic within this method. public boolean showAutofillDialog(@NonNull View view, int virtualId) { Objects.requireNonNull(view); if (shouldShowAutofillDialog(getAutofillId(view, virtualId))) { diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 67f284b437b0..dbfcca9d632a 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -111,6 +111,7 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewParent; +import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -129,6 +130,9 @@ import android.view.textclassifier.TextClassificationManager; import android.widget.AdapterView.OnItemClickListener; import android.widget.TextView.Drawables; import android.widget.TextView.OnEditorActionListener; +import android.window.OnBackInvokedCallback; +import android.window.OnBackInvokedDispatcher; +import android.window.WindowOnBackInvokedDispatcher; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.EditableInputConnection; @@ -235,6 +239,14 @@ public class Editor { private boolean mSelectionControllerEnabled; private final boolean mHapticTextHandleEnabled; + /** Handles OnBackInvokedCallback back dispatch */ + private final OnBackInvokedCallback mBackCallback = new OnBackInvokedCallback() { + @Override + public void onBackInvoked() { + stopTextActionMode(); + } + }; + private boolean mBackCallbackRegistered; @Nullable private MagnifierMotionAnimator mMagnifierAnimator; @@ -753,6 +765,35 @@ public class Editor { stopTextActionModeWithPreservingSelection(); mDefaultOnReceiveContentListener.clearInputConnectionInfo(); + unregisterOnBackInvokedCallback(); + } + + private void unregisterOnBackInvokedCallback() { + if (!mBackCallbackRegistered) { + return; + } + ViewRootImpl viewRootImpl = getTextView().getViewRootImpl(); + if (viewRootImpl != null + && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled( + viewRootImpl.mContext)) { + viewRootImpl.getOnBackInvokedDispatcher() + .unregisterOnBackInvokedCallback(mBackCallback); + mBackCallbackRegistered = false; + } + } + + private void registerOnBackInvokedCallback() { + if (mBackCallbackRegistered) { + return; + } + ViewRootImpl viewRootImpl = mTextView.getViewRootImpl(); + if (viewRootImpl != null + && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled( + viewRootImpl.mContext)) { + viewRootImpl.getOnBackInvokedDispatcher().registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback); + mBackCallbackRegistered = true; + } } private void discardTextDisplayLists() { @@ -2370,6 +2411,7 @@ public class Editor { new TextActionModeCallback(TextActionMode.INSERTION); mTextActionMode = mTextView.startActionMode( actionModeCallback, ActionMode.TYPE_FLOATING); + registerOnBackInvokedCallback(); if (mTextActionMode != null && getInsertionController() != null) { getInsertionController().show(); } @@ -2485,6 +2527,7 @@ public class Editor { ActionMode.Callback actionModeCallback = new TextActionModeCallback(actionMode); mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING); + registerOnBackInvokedCallback(); final boolean selectableText = mTextView.isTextEditable() || mTextView.isTextSelectable(); if (actionMode == TextActionMode.TEXT_LINK && !selectableText @@ -2660,6 +2703,7 @@ public class Editor { // This will hide the mSelectionModifierCursorController mTextActionMode.finish(); } + unregisterOnBackInvokedCallback(); } private void stopTextActionModeWithPreservingSelection() { diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index 9c9baf35949b..f1dc5e7050fb 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; @@ -30,10 +31,14 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.widget.SeekBar.OnSeekBarChangeListener; +import android.window.OnBackInvokedCallback; +import android.window.OnBackInvokedDispatcher; +import android.window.WindowOnBackInvokedDispatcher; import com.android.internal.policy.PhoneWindow; @@ -115,6 +120,27 @@ public class MediaController extends FrameLayout { private CharSequence mPlayDescription; private CharSequence mPauseDescription; private final AccessibilityManager mAccessibilityManager; + private boolean mBackCallbackRegistered; + /** Handles back invocation */ + private final OnBackInvokedCallback mBackCallback = new OnBackInvokedCallback() { + @Override + public void onBackInvoked() { + hide(); + } + }; + /** Handles decor view attach state change */ + private final OnAttachStateChangeListener mAttachStateListener = + new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(@NonNull View v) { + registerOnBackInvokedCallback(); + } + + @Override + public void onViewDetachedFromWindow(@NonNull View v) { + unregisterOnBackInvokedCallback(); + } + }; public MediaController(Context context, AttributeSet attrs) { super(context, attrs); @@ -151,6 +177,7 @@ public class MediaController extends FrameLayout { mWindow.requestFeature(Window.FEATURE_NO_TITLE); mDecor = mWindow.getDecorView(); mDecor.setOnTouchListener(mTouchListener); + mDecor.addOnAttachStateChangeListener(mAttachStateListener); mWindow.setContentView(this); mWindow.setBackgroundDrawableResource(android.R.color.transparent); @@ -395,6 +422,7 @@ public class MediaController extends FrameLayout { removeCallbacks(mFadeOut); postDelayed(mFadeOut, timeout); } + registerOnBackInvokedCallback(); } public boolean isShowing() { @@ -416,6 +444,7 @@ public class MediaController extends FrameLayout { Log.w("MediaController", "already removed"); } mShowing = false; + unregisterOnBackInvokedCallback(); } } @@ -718,6 +747,35 @@ public class MediaController extends FrameLayout { } } + private void unregisterOnBackInvokedCallback() { + if (!mBackCallbackRegistered) { + return; + } + ViewRootImpl viewRootImpl = mDecor.getViewRootImpl(); + if (viewRootImpl != null + && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled( + viewRootImpl.mContext)) { + viewRootImpl.getOnBackInvokedDispatcher() + .unregisterOnBackInvokedCallback(mBackCallback); + } + mBackCallbackRegistered = false; + } + + private void registerOnBackInvokedCallback() { + if (mBackCallbackRegistered) { + return; + } + + ViewRootImpl viewRootImpl = mDecor.getViewRootImpl(); + if (viewRootImpl != null + && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled( + viewRootImpl.mContext)) { + viewRootImpl.getOnBackInvokedDispatcher().registerOnBackInvokedCallback( + OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback); + mBackCallbackRegistered = true; + } + } + public interface MediaPlayerControl { void start(); void pause(); diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java index 942be21b1ade..1713d842560b 100644 --- a/core/java/android/widget/TextViewTranslationCallback.java +++ b/core/java/android/widget/TextViewTranslationCallback.java @@ -89,7 +89,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { originalTranslationMethod); } final TransformationMethod transformation = mTranslationTransformation; - runWithAnimation( + runChangeTextWithAnimationIfNeeded( (TextView) view, () -> { mIsShowingTranslation = true; @@ -122,7 +122,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { if (mTranslationTransformation != null) { final TransformationMethod transformation = mTranslationTransformation.getOriginalTransformationMethod(); - runWithAnimation( + runChangeTextWithAnimationIfNeeded( (TextView) view, () -> { mIsShowingTranslation = false; @@ -232,10 +232,16 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { * Applies a simple text alpha animation when toggling between original and translated text. The * text is fully faded out, then swapped to the new text, then the fading is reversed. * - * @param runnable the operation to run on the view after the text is faded out, to change to - * displaying the original or translated text. + * @param changeTextRunnable the operation to run on the view after the text is faded out, to + * change to displaying the original or translated text. */ - private void runWithAnimation(TextView view, Runnable runnable) { + private void runChangeTextWithAnimationIfNeeded(TextView view, Runnable changeTextRunnable) { + boolean areAnimatorsEnabled = ValueAnimator.areAnimatorsEnabled(); + if (!areAnimatorsEnabled) { + // The animation is disabled, just change display text + changeTextRunnable.run(); + return; + } if (mAnimator != null) { mAnimator.end(); // Note: mAnimator is now null; do not use again here. @@ -269,7 +275,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { @Override public void onAnimationRepeat(Animator animation) { - runnable.run(); + changeTextRunnable.run(); } }); mAnimator.start(); diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 35c959493f23..f2db5648a75f 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -269,6 +269,20 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Used in conjunction with a shell-transition call (usually finishTransition). This is + * basically a message to the transition system that a particular task should NOT go into + * PIP even though it normally would. This is to deal with some edge-case situations where + * Recents will "commit" the transition to go home, but then not actually go-home. + * @hide + */ + @NonNull + public WindowContainerTransaction setDoNotPip(@NonNull WindowContainerToken container) { + Change chg = getOrCreateChange(container.asBinder()); + chg.mChangeMask |= Change.CHANGE_FORCE_NO_PIP; + return this; + } + + /** * Reparents a container into another one. The effect of a {@code null} parent can vary. For * example, reparenting a stack to {@code null} will reparent it to its display. * @@ -790,6 +804,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_HIDDEN = 1 << 3; public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4; public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5; + public static final int CHANGE_FORCE_NO_PIP = 1 << 6; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; diff --git a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java index 31c38220ccc2..2d6c77fdc41b 100644 --- a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java +++ b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java @@ -56,7 +56,11 @@ public class BlockedAppStreamingActivity extends AlertActivity { CharSequence streamedDeviceName = intent.getCharSequenceExtra(EXTRA_STREAMED_DEVICE); if (!TextUtils.isEmpty(streamedDeviceName)) { - mAlertParams.mTitle = getString(R.string.app_streaming_blocked_title, appLabel); + mAlertParams.mTitle = + TextUtils.equals(activityInfo.packageName, + getPackageManager().getPermissionControllerPackageName()) + ? getString(R.string.app_streaming_blocked_title_for_permission_dialog) + : getString(R.string.app_streaming_blocked_title, appLabel); mAlertParams.mMessage = getString(R.string.app_streaming_blocked_message, streamedDeviceName); } else { diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index c2e145eccb97..96728ed89b70 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -28,7 +28,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.SharedElementCallback; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; @@ -71,11 +70,9 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; -import android.os.IBinder; import android.os.Message; import android.os.Parcelable; import android.os.PatternMatcher; -import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; import android.os.UserManager; @@ -761,25 +758,17 @@ public class ChooserActivity extends ResolverActivity implements return false; } - try { - Intent delegationIntent = new Intent(); - final ComponentName delegateActivity = ComponentName.unflattenFromString( - Resources.getSystem().getString(R.string.config_chooserActivity)); - IBinder permissionToken = ActivityTaskManager.getService() - .requestStartActivityPermissionToken(delegateActivity); - delegationIntent.setComponent(delegateActivity); - delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent()); - delegationIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken); - delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); - - // Don't close until the delegate finishes, or the token will be invalidated. - mAwaitingDelegateResponse = true; - startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER); - return true; - } catch (RemoteException e) { - Log.e(TAG, e.toString()); - } - return false; + Intent delegationIntent = new Intent(); + final ComponentName delegateActivity = ComponentName.unflattenFromString( + Resources.getSystem().getString(R.string.config_chooserActivity)); + delegationIntent.setComponent(delegateActivity); + delegationIntent.putExtra(Intent.EXTRA_INTENT, getIntent()); + delegationIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); + + // Don't close until the delegate finishes, or the token will be invalidated. + mAwaitingDelegateResponse = true; + startActivityForResult(delegationIntent, REQUEST_CODE_RETURN_FROM_DELEGATE_CHOOSER); + return true; } @Override diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 6e7690678d21..070d8ff945ba 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -207,7 +207,6 @@ public class IntentForwarderActivity extends Activity { startActivityAsCaller( newIntent, /* options= */ null, - /* permissionToken= */ null, /* ignoreTargetSecurity= */ false, userId); } catch (RuntimeException e) { @@ -231,7 +230,7 @@ public class IntentForwarderActivity extends Activity { return; } sanitizeIntent(innerIntent); - startActivityAsCaller(intentReceived, null, null, false, getUserId()); + startActivityAsCaller(intentReceived, null, false, getUserId()); finish(); } @@ -251,7 +250,7 @@ public class IntentForwarderActivity extends Activity { sanitizeIntent(intentReceived); intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile); intentReceived.putExtra(EXTRA_CALLING_USER, UserHandle.of(callingUserId)); - startActivityAsCaller(intentReceived, null, null, false, userId); + startActivityAsCaller(intentReceived, null, false, userId); finish(); } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 5ebb148760c6..dc68e16e2eb6 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1463,7 +1463,7 @@ public class ResolverActivity extends Activity implements int userId) { // Note: this method will be overridden in the delegate implementation to use the passed-in // permission token. - startActivityAsCaller(intent, options, null, false, userId); + startActivityAsCaller(intent, options, false, userId); return true; } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index f623a73d6f4e..4b2034799d41 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -69,6 +69,7 @@ import android.os.connectivity.GpsBatteryStats; import android.os.connectivity.WifiActivityEnergyInfo; import android.os.connectivity.WifiBatteryStats; import android.provider.Settings; +import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.NetworkType; import android.telephony.CellSignalStrength; import android.telephony.CellSignalStrengthLte; @@ -6830,6 +6831,27 @@ public class BatteryStatsImpl extends BatteryStats { } } + @RadioAccessTechnology + private static int mapRadioAccessNetworkTypeToRadioAccessTechnology( + @AccessNetworkConstants.RadioAccessNetworkType int dataType) { + switch (dataType) { + case AccessNetworkConstants.AccessNetworkType.NGRAN: + return RADIO_ACCESS_TECHNOLOGY_NR; + case AccessNetworkConstants.AccessNetworkType.EUTRAN: + return RADIO_ACCESS_TECHNOLOGY_LTE; + case AccessNetworkConstants.AccessNetworkType.UNKNOWN: //fallthrough + case AccessNetworkConstants.AccessNetworkType.GERAN: //fallthrough + case AccessNetworkConstants.AccessNetworkType.UTRAN: //fallthrough + case AccessNetworkConstants.AccessNetworkType.CDMA2000: //fallthrough + case AccessNetworkConstants.AccessNetworkType.IWLAN: + return RADIO_ACCESS_TECHNOLOGY_OTHER; + default: + Slog.w(TAG, + "Unhandled RadioAccessNetworkType (" + dataType + "), mapping to OTHER"); + return RADIO_ACCESS_TECHNOLOGY_OTHER; + } + } + @GuardedBy("this") public void noteWifiOnLocked() { noteWifiOnLocked(mClock.elapsedRealtime(), mClock.uptimeMillis()); @@ -13721,66 +13743,7 @@ public class BatteryStatsImpl extends BatteryStats { mTmpRailStats.resetCellularTotalEnergyUsed(); } - // Proportionally smear Rx and Tx times across each RAt - final int levelCount = CellSignalStrength.getNumSignalStrengthLevels(); - long[] perSignalStrengthActiveTimeMs = new long[levelCount]; - long totalActiveTimeMs = 0; - - for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) { - final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat]; - if (ratStats == null) continue; - - final int freqCount = ratStats.getFrequencyRangeCount(); - for (int freq = 0; freq < freqCount; freq++) { - for (int level = 0; level < levelCount; level++) { - final long durationMs = ratStats.getTimeSinceMark(freq, level, - elapsedRealtimeMs); - perSignalStrengthActiveTimeMs[level] += durationMs; - totalActiveTimeMs += durationMs; - } - } - } - - if (totalActiveTimeMs != 0) { - // Smear the provided Tx/Rx durations across each RAT, frequency, and signal - // strength. - for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) { - final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat]; - if (ratStats == null) continue; - - final int freqCount = ratStats.getFrequencyRangeCount(); - for (int freq = 0; freq < freqCount; freq++) { - long frequencyDurationMs = 0; - for (int level = 0; level < levelCount; level++) { - final long durationMs = ratStats.getTimeSinceMark(freq, level, - elapsedRealtimeMs); - final long totalLvlDurationMs = - perSignalStrengthActiveTimeMs[level]; - if (totalLvlDurationMs == 0) continue; - final long totalTxLvlDurations = - deltaInfo.getTransmitDurationMillisAtPowerLevel(level); - // Smear HAL provided Tx power level duration based on active modem - // duration in a given state. (Add totalLvlDurationMs / 2 before - // the integer division with totalLvlDurationMs for rounding.) - final long proportionalTxDurationMs = - (durationMs * totalTxLvlDurations - + (totalLvlDurationMs / 2)) / totalLvlDurationMs; - ratStats.incrementTxDuration(freq, level, proportionalTxDurationMs); - frequencyDurationMs += durationMs; - } - final long totalRxDuration = deltaInfo.getReceiveTimeMillis(); - // Smear HAL provided Rx power duration based on active modem - // duration in a given state. (Add totalActiveTimeMs / 2 before the - // integer division with totalActiveTimeMs for rounding.) - final long proportionalRxDurationMs = - (frequencyDurationMs * totalRxDuration + (totalActiveTimeMs - / 2)) / totalActiveTimeMs; - ratStats.incrementRxDuration(freq, proportionalRxDurationMs); - } - - ratStats.setMark(elapsedRealtimeMs); - } - } + incrementPerRatDataLocked(deltaInfo, elapsedRealtimeMs); } long totalAppRadioTimeUs = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked( elapsedRealtimeMs * 1000); @@ -13931,6 +13894,100 @@ public class BatteryStatsImpl extends BatteryStats { } } + @GuardedBy("this") + private void incrementPerRatDataLocked(ModemActivityInfo deltaInfo, long elapsedRealtimeMs) { + final int infoSize = deltaInfo.getSpecificInfoLength(); + if (infoSize == 1 && deltaInfo.getSpecificInfoRat(0) + == AccessNetworkConstants.AccessNetworkType.UNKNOWN + && deltaInfo.getSpecificInfoFrequencyRange(0) + == ServiceState.FREQUENCY_RANGE_UNKNOWN) { + // Specific info data unavailable. Proportionally smear Rx and Tx times across each RAT. + final int levelCount = CellSignalStrength.getNumSignalStrengthLevels(); + long[] perSignalStrengthActiveTimeMs = new long[levelCount]; + long totalActiveTimeMs = 0; + + for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) { + final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat]; + if (ratStats == null) continue; + + final int freqCount = ratStats.getFrequencyRangeCount(); + for (int freq = 0; freq < freqCount; freq++) { + for (int level = 0; level < levelCount; level++) { + final long durationMs = ratStats.getTimeSinceMark(freq, level, + elapsedRealtimeMs); + perSignalStrengthActiveTimeMs[level] += durationMs; + totalActiveTimeMs += durationMs; + } + } + } + if (totalActiveTimeMs != 0) { + // Smear the provided Tx/Rx durations across each RAT, frequency, and signal + // strength. + for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) { + final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat]; + if (ratStats == null) continue; + + final int freqCount = ratStats.getFrequencyRangeCount(); + for (int freq = 0; freq < freqCount; freq++) { + long frequencyDurationMs = 0; + for (int level = 0; level < levelCount; level++) { + final long durationMs = ratStats.getTimeSinceMark(freq, level, + elapsedRealtimeMs); + final long totalLvlDurationMs = + perSignalStrengthActiveTimeMs[level]; + if (totalLvlDurationMs == 0) continue; + final long totalTxLvlDurations = + deltaInfo.getTransmitDurationMillisAtPowerLevel(level); + // Smear HAL provided Tx power level duration based on active modem + // duration in a given state. (Add totalLvlDurationMs / 2 before + // the integer division with totalLvlDurationMs for rounding.) + final long proportionalTxDurationMs = + (durationMs * totalTxLvlDurations + + (totalLvlDurationMs / 2)) / totalLvlDurationMs; + ratStats.incrementTxDuration(freq, level, proportionalTxDurationMs); + frequencyDurationMs += durationMs; + } + final long totalRxDuration = deltaInfo.getReceiveTimeMillis(); + // Smear HAL provided Rx power duration based on active modem + // duration in a given state. (Add totalActiveTimeMs / 2 before the + // integer division with totalActiveTimeMs for rounding.) + final long proportionalRxDurationMs = + (frequencyDurationMs * totalRxDuration + (totalActiveTimeMs + / 2)) / totalActiveTimeMs; + ratStats.incrementRxDuration(freq, proportionalRxDurationMs); + } + + } + } + } else { + // Specific data available. + for (int index = 0; index < infoSize; index++) { + final int rat = deltaInfo.getSpecificInfoRat(index); + final int freq = deltaInfo.getSpecificInfoFrequencyRange(index); + + // Map RadioAccessNetworkType to course grain RadioAccessTechnology. + final int ratBucket = mapRadioAccessNetworkTypeToRadioAccessTechnology(rat); + final RadioAccessTechnologyBatteryStats ratStats = getRatBatteryStatsLocked( + ratBucket); + + final long rxTimeMs = deltaInfo.getReceiveTimeMillis(rat, freq); + final int[] txTimesMs = deltaInfo.getTransmitTimeMillis(rat, freq); + + ratStats.incrementRxDuration(freq, rxTimeMs); + final int numTxLvl = txTimesMs.length; + for (int lvl = 0; lvl < numTxLvl; lvl++) { + ratStats.incrementTxDuration(freq, lvl, txTimesMs[lvl]); + } + } + } + + for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) { + final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat]; + if (ratStats == null) continue; + ratStats.setMark(elapsedRealtimeMs); + } + } + /** * Add modem tx power to history * Device is said to be in high cellular transmit power when it has spent most of the transmit diff --git a/core/java/com/android/internal/os/BatteryUsageStatsStore.java b/core/java/com/android/internal/os/BatteryUsageStatsStore.java index af82f40013d8..09c9cfcd2e71 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsStore.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsStore.java @@ -22,6 +22,7 @@ import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.Handler; import android.util.AtomicFile; +import android.util.Log; import android.util.LongArray; import android.util.Slog; import android.util.TypedXmlPullParser; @@ -47,6 +48,7 @@ import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.TreeMap; +import java.util.concurrent.locks.ReentrantLock; /** * A storage mechanism for BatteryUsageStats snapshots. @@ -73,6 +75,8 @@ public class BatteryUsageStatsStore { private boolean mSystemReady; private final File mStoreDir; private final File mLockFile; + private final ReentrantLock mFileLock = new ReentrantLock(); + private FileLock mJvmLock; private final AtomicFile mConfigFile; private final long mMaxStorageBytes; private final Handler mHandler; @@ -120,11 +124,11 @@ public class BatteryUsageStatsStore { } private void storeBatteryUsageStats(BatteryUsageStats stats) { - try (FileLock lock = lockSnapshotDirectory()) { + lockSnapshotDirectory(); + try { if (!mStoreDir.exists()) { if (!mStoreDir.mkdirs()) { - Slog.e(TAG, - "Could not create a directory for battery usage stats snapshots"); + Slog.e(TAG, "Could not create a directory for battery usage stats snapshots"); return; } } @@ -136,8 +140,8 @@ public class BatteryUsageStatsStore { } removeOldSnapshotsLocked(); - } catch (IOException e) { - Slog.e(TAG, "Cannot lock battery usage stats directory", e); + } finally { + unlockSnapshotDirectory(); } } @@ -147,7 +151,8 @@ public class BatteryUsageStatsStore { */ public long[] listBatteryUsageStatsTimestamps() { LongArray timestamps = new LongArray(100); - try (FileLock lock = lockSnapshotDirectory()) { + lockSnapshotDirectory(); + try { for (File file : mStoreDir.listFiles()) { String fileName = file.getName(); if (fileName.endsWith(SNAPSHOT_FILE_EXTENSION)) { @@ -161,8 +166,8 @@ public class BatteryUsageStatsStore { } } } - } catch (IOException e) { - Slog.e(TAG, "Cannot lock battery usage stats directory", e); + } finally { + unlockSnapshotDirectory(); } return timestamps.toArray(); } @@ -173,15 +178,16 @@ public class BatteryUsageStatsStore { */ @Nullable public BatteryUsageStats loadBatteryUsageStats(long timestamp) { - try (FileLock lock = lockSnapshotDirectory()) { + lockSnapshotDirectory(); + try { File file = makeSnapshotFilename(timestamp); try { return readXmlFileLocked(file); } catch (Exception e) { Slog.e(TAG, "Cannot read battery usage stats", e); } - } catch (IOException e) { - Slog.e(TAG, "Cannot lock battery usage stats directory", e); + } finally { + unlockSnapshotDirectory(); } return null; } @@ -192,7 +198,8 @@ public class BatteryUsageStatsStore { */ public void setLastBatteryUsageStatsBeforeResetAtomPullTimestamp(long timestamp) { Properties props = new Properties(); - try (FileLock lock = lockSnapshotDirectory()) { + lockSnapshotDirectory(); + try { try (InputStream in = mConfigFile.openRead()) { props.load(in); } catch (IOException e) { @@ -209,8 +216,8 @@ public class BatteryUsageStatsStore { mConfigFile.failWrite(out); Slog.e(TAG, "Cannot save config file " + mConfigFile, e); } - } catch (IOException e) { - Slog.e(TAG, "Cannot lock battery usage stats directory", e); + } finally { + unlockSnapshotDirectory(); } } @@ -220,23 +227,41 @@ public class BatteryUsageStatsStore { */ public long getLastBatteryUsageStatsBeforeResetAtomPullTimestamp() { Properties props = new Properties(); - try (FileLock lock = lockSnapshotDirectory()) { + lockSnapshotDirectory(); + try { try (InputStream in = mConfigFile.openRead()) { props.load(in); } catch (IOException e) { Slog.e(TAG, "Cannot load config file " + mConfigFile, e); } - } catch (IOException e) { - Slog.e(TAG, "Cannot lock battery usage stats directory", e); + } finally { + unlockSnapshotDirectory(); } return Long.parseLong( props.getProperty(BATTERY_USAGE_STATS_BEFORE_RESET_TIMESTAMP_PROPERTY, "0")); } - private FileLock lockSnapshotDirectory() throws IOException { - mLockFile.getParentFile().mkdirs(); - mLockFile.createNewFile(); - return FileChannel.open(mLockFile.toPath(), StandardOpenOption.WRITE).lock(); + private void lockSnapshotDirectory() { + mFileLock.lock(); + + // Lock the directory from access by other JVMs + try { + mLockFile.getParentFile().mkdirs(); + mLockFile.createNewFile(); + mJvmLock = FileChannel.open(mLockFile.toPath(), StandardOpenOption.WRITE).lock(); + } catch (IOException e) { + Log.e(TAG, "Cannot lock snapshot directory", e); + } + } + + private void unlockSnapshotDirectory() { + try { + mJvmLock.close(); + } catch (IOException e) { + Log.e(TAG, "Cannot unlock snapshot directory", e); + } finally { + mFileLock.unlock(); + } } /** diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java index fd8534d45b2b..e2d250589a8f 100644 --- a/core/java/com/android/internal/policy/TransitionAnimation.java +++ b/core/java/com/android/internal/policy/TransitionAnimation.java @@ -101,6 +101,10 @@ public class TransitionAnimation { private static final String DEFAULT_PACKAGE = "android"; + // TODO (b/215515255): remove once we full migrate to shell transitions + private static final boolean SHELL_TRANSITIONS_ENABLED = + SystemProperties.getBoolean("persist.wm.debug.shell_transit", false); + private final Context mContext; private final String mTag; @@ -255,6 +259,9 @@ public class TransitionAnimation { resId = ent.array.getResourceId(animAttr, 0); } } + if (!SHELL_TRANSITIONS_ENABLED) { + resId = updateToLegacyIfNeeded(resId); + } resId = updateToTranslucentAnimIfNeeded(resId, transit); if (ResourceId.isValid(resId)) { return loadAnimationSafely(context, resId, mTag); @@ -262,6 +269,24 @@ public class TransitionAnimation { return null; } + /** + * Replace animations that are not compatible with the legacy transition system with ones that + * are compatible with it. + * TODO (b/215515255): remove once we full migrate to shell transitions + */ + private int updateToLegacyIfNeeded(int anim) { + if (anim == R.anim.activity_open_enter) { + return R.anim.activity_open_enter_legacy; + } else if (anim == R.anim.activity_open_exit) { + return R.anim.activity_open_exit_legacy; + } else if (anim == R.anim.activity_close_enter) { + return R.anim.activity_close_enter_legacy; + } else if (anim == R.anim.activity_close_exit) { + return R.anim.activity_close_exit_legacy; + } + return anim; + } + /** Load animation by attribute Id from a specific AnimationStyle resource. */ @Nullable public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr, diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 3cbf72034897..fc5da138d64a 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -77,8 +77,6 @@ public class LockPatternView extends View { private static final boolean PROFILE_DRAWING = false; private static final int LINE_END_ANIMATION_DURATION_MILLIS = 50; - private static final int LINE_FADE_OUT_DURATION_MILLIS = 500; - private static final int LINE_FADE_OUT_DELAY_MILLIS = 150; private static final int DOT_ACTIVATION_DURATION_MILLIS = 50; private static final int DOT_RADIUS_INCREASE_DURATION_MILLIS = 96; private static final int DOT_RADIUS_DECREASE_DURATION_MILLIS = 192; @@ -89,6 +87,8 @@ public class LockPatternView extends View { private final int mDotSizeActivated; private final float mDotHitFactor; private final int mPathWidth; + private final int mLineFadeOutAnimationDurationMs; + private final int mLineFadeOutAnimationDelayMs; private boolean mDrawingProfilingStarted = false; @@ -346,6 +346,11 @@ public class LockPatternView extends View { mPathWidth = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_line_width); mPathPaint.setStrokeWidth(mPathWidth); + mLineFadeOutAnimationDurationMs = + getResources().getInteger(R.integer.lock_pattern_line_fade_out_duration); + mLineFadeOutAnimationDelayMs = + getResources().getInteger(R.integer.lock_pattern_line_fade_out_delay); + mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size); mDotSizeActivated = getResources().getDimensionPixelSize( R.dimen.lock_pattern_dot_size_activated); @@ -831,7 +836,7 @@ public class LockPatternView extends View { deactivateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS); AnimatorSet set = new AnimatorSet(); set.play(deactivateAnimator) - .after(LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS + .after(mLineFadeOutAnimationDelayMs + mLineFadeOutAnimationDurationMs - DOT_ACTIVATION_DURATION_MILLIS * 2) .after(activateAnimator); return set; @@ -862,8 +867,8 @@ public class LockPatternView extends View { private Animator createLineDisappearingAnimation() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.addUpdateListener(animation -> invalidate()); - valueAnimator.setStartDelay(LINE_FADE_OUT_DELAY_MILLIS); - valueAnimator.setDuration(LINE_FADE_OUT_DURATION_MILLIS); + valueAnimator.setStartDelay(mLineFadeOutAnimationDelayMs); + valueAnimator.setDuration(mLineFadeOutAnimationDurationMs); return valueAnimator; } @@ -1278,14 +1283,14 @@ public class LockPatternView extends View { float fadeAwayProgress; if (mFadePattern) { if (elapsedRealtime - lineFadeStart - >= LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS) { + >= mLineFadeOutAnimationDelayMs + mLineFadeOutAnimationDurationMs) { // Time for this segment animation is out so we don't need to draw it. return; } // Set this line segment to fade away animated. fadeAwayProgress = Math.max( - ((float) (elapsedRealtime - lineFadeStart - LINE_FADE_OUT_DELAY_MILLIS)) - / LINE_FADE_OUT_DURATION_MILLIS, 0f); + ((float) (elapsedRealtime - lineFadeStart - mLineFadeOutAnimationDelayMs)) + / mLineFadeOutAnimationDurationMs, 0f); drawFadingAwayLineSegment(canvas, startX, startY, endX, endY, fadeAwayProgress); } else { mPathPaint.setAlpha(255); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f52f4a754af3..0353e4be9972 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -719,6 +719,92 @@ <protected-broadcast android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" /> <protected-broadcast android:name="android.app.action.SHOW_NEW_USER_DISCLAIMER" /> + <!-- Moved from packages/services/Telephony in T --> + <protected-broadcast android:name="android.telecom.action.CURRENT_TTY_MODE_CHANGED" /> + <protected-broadcast android:name="android.intent.action.SERVICE_STATE" /> + <protected-broadcast android:name="android.intent.action.RADIO_TECHNOLOGY" /> + <protected-broadcast android:name="android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED" /> + <protected-broadcast android:name="android.intent.action.EMERGENCY_CALL_STATE_CHANGED" /> + <protected-broadcast android:name="android.intent.action.SIG_STR" /> + <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" /> + <protected-broadcast android:name="android.intent.action.DATA_STALL_DETECTED" /> + <protected-broadcast android:name="android.intent.action.SIM_STATE_CHANGED" /> + <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" /> + <protected-broadcast android:name="android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS" /> + <protected-broadcast android:name="android.intent.action.ACTION_MDN_STATE_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.SERVICE_PROVIDERS_UPDATED" /> + <protected-broadcast android:name="android.provider.Telephony.SIM_FULL" /> + <protected-broadcast android:name="com.android.internal.telephony.carrier_key_download_alarm" /> + <protected-broadcast android:name="com.android.internal.telephony.data-restart-trysetup" /> + <protected-broadcast android:name="com.android.internal.telephony.data-stall" /> + <protected-broadcast android:name="com.android.internal.telephony.provisioning_apn_alarm" /> + <protected-broadcast android:name="android.intent.action.DATA_SMS_RECEIVED" /> + <protected-broadcast android:name="android.provider.Telephony.SMS_RECEIVED" /> + <protected-broadcast android:name="android.provider.Telephony.SMS_DELIVER" /> + <protected-broadcast android:name="android.provider.Telephony.SMS_REJECTED" /> + <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_DELIVER" /> + <protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" /> + <protected-broadcast android:name="android.provider.Telephony.SMS_CB_RECEIVED" /> + <protected-broadcast android:name="android.provider.action.SMS_EMERGENCY_CB_RECEIVED" /> + <protected-broadcast android:name="android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED" /> + <protected-broadcast android:name="android.provider.Telephony.SECRET_CODE" /> + <protected-broadcast android:name="com.android.internal.stk.command" /> + <protected-broadcast android:name="com.android.internal.stk.session_end" /> + <protected-broadcast android:name="com.android.internal.stk.icc_status_change" /> + <protected-broadcast android:name="com.android.internal.stk.alpha_notify" /> + <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" /> + <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" /> + <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE" /> + <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" /> + <protected-broadcast android:name="com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE" /> + <protected-broadcast android:name="com.android.internal.telephony.PROVISION" /> + <protected-broadcast android:name="com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED" /> + <protected-broadcast android:name="com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED" /> + <protected-broadcast android:name="com.android.intent.isim_refresh" /> + <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_AVAILABLE" /> + <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_UNAVAILABLE" /> + <protected-broadcast android:name="com.android.ims.ACTION_RCS_SERVICE_DIED" /> + <protected-broadcast android:name="com.android.ims.ACTION_PRESENCE_CHANGED" /> + <protected-broadcast android:name="com.android.ims.ACTION_PUBLISH_STATUS_CHANGED" /> + <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" /> + <protected-broadcast android:name="com.android.ims.IMS_SERVICE_DOWN" /> + <protected-broadcast android:name="com.android.ims.IMS_INCOMING_CALL" /> + <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" /> + <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_DOWN" /> + <protected-broadcast android:name="com.android.imsconnection.DISCONNECTED" /> + <protected-broadcast android:name="com.android.intent.action.IMS_FEATURE_CHANGED" /> + <protected-broadcast android:name="com.android.intent.action.IMS_CONFIG_CHANGED" /> + <protected-broadcast android:name="android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR" /> + <protected-broadcast android:name="com.android.phone.vvm.omtp.sms.REQUEST_SENT" /> + <protected-broadcast android:name="com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT" /> + <protected-broadcast android:name="com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" /> + <protected-broadcast android:name="com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO" /> + <protected-broadcast android:name="com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD" /> + <protected-broadcast android:name="com.android.internal.telephony.action.COUNTRY_OVERRIDE" /> + <protected-broadcast android:name="com.android.internal.telephony.OPEN_DEFAULT_SMS_APP" /> + <protected-broadcast android:name="com.android.internal.telephony.ACTION_TEST_OVERRIDE_CARRIER_ID" /> + <protected-broadcast android:name="android.telephony.action.SIM_CARD_STATE_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.SIM_APPLICATION_STATE_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.SIM_SLOT_STATUS_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.TOGGLE_PROVISION" /> + <protected-broadcast android:name="android.telephony.action.NETWORK_COUNTRY_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.MULTI_SIM_CONFIG_CHANGED" /> + <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_RESET" /> + <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_PCO_VALUE" /> + <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE" /> + <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_REDIRECTED" /> + <protected-broadcast android:name="android.telephony.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" /> + <protected-broadcast android:name="com.android.phone.settings.CARRIER_PROVISIONING" /> + <protected-broadcast android:name="com.android.phone.settings.TRIGGER_CARRIER_PROVISIONING" /> + <protected-broadcast android:name="com.android.internal.telephony.ACTION_VOWIFI_ENABLED" /> + <protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" /> + <protected-broadcast android:name="android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED" /> + <protected-broadcast android:name="android.intent.action.ACTION_MANAGED_ROAMING_IND" /> + <protected-broadcast android:name="android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE" /> + <!-- Added in T --> <protected-broadcast android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES" /> <protected-broadcast android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED" /> @@ -3736,29 +3822,6 @@ <permission android:name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL" android:protectionLevel="signature|privileged" /> - <!-- ========================================= --> - <!-- Permissions for AdServices --> - <!-- ========================================= --> - <eat-comment /> - - <!-- Allows an application to access AdServices Topics API. --> - <permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS" - android:label="@string/permlab_accessAdServicesTopics" - android:description="@string/permdesc_accessAdServicesTopics" - android:protectionLevel="normal" /> - - <!-- Allows an application to access AdServices Attribution APIs. --> - <permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" - android:label="@string/permlab_accessAdServicesAttribution" - android:description="@string/permdesc_accessAdServicesAttribution" - android:protectionLevel="normal" /> - - <!-- Allows an application to access AdServices Custom Audiences APIs. --> - <permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCES" - android:label="@string/permlab_accessAdServicesCustomAudiences" - android:description="@string/permdesc_accessAdServicesCustomAudiences" - android:protectionLevel="normal" /> - <!-- ==================================== --> <!-- Private permissions --> <!-- ==================================== --> @@ -6882,6 +6945,9 @@ </intent-filter> </receiver> + <!-- Broadcast Receiver listen to sufficient verifier requests from Package Manager + when install new SDK, to verifier SDK code during installation time + and terminate install if SDK not compatible with privacy sandbox restrictions. --> <receiver android:name="com.android.server.sdksandbox.SdkSandboxVerifierReceiver" android:exported="false"> <intent-filter> diff --git a/core/res/res/anim/activity_close_enter_legacy.xml b/core/res/res/anim/activity_close_enter_legacy.xml new file mode 100644 index 000000000000..9fa7c5498ea6 --- /dev/null +++ b/core/res/res/anim/activity_close_enter_legacy.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + <scale + android:fromXScale="1.1" + android:toXScale="1" + android:fromYScale="1.1" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:duration="400"/> +</set>
\ No newline at end of file diff --git a/core/res/res/anim/activity_close_exit_legacy.xml b/core/res/res/anim/activity_close_exit_legacy.xml new file mode 100644 index 000000000000..1599ae8cb19f --- /dev/null +++ b/core/res/res/anim/activity_close_exit_legacy.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" + android:zAdjustment="top"> + <alpha + android:fromAlpha="1" + android:toAlpha="0.0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="33" + android:duration="50"/> + <scale + android:fromXScale="1" + android:toXScale="0.9" + android:fromYScale="1" + android:toYScale="0.9" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:duration="400"/> +</set> diff --git a/core/res/res/anim/activity_open_enter_legacy.xml b/core/res/res/anim/activity_open_enter_legacy.xml new file mode 100644 index 000000000000..38d3e8ed06ce --- /dev/null +++ b/core/res/res/anim/activity_open_enter_legacy.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?><!-- +/* +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + <alpha + android:fromAlpha="0" + android:toAlpha="1.0" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="50" + android:duration="50"/> + <scale + android:fromXScale="0.85" + android:toXScale="1" + android:fromYScale="0.85" + android:toYScale="1" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:duration="400"/> +</set> diff --git a/core/res/res/anim/activity_open_exit_legacy.xml b/core/res/res/anim/activity_open_exit_legacy.xml new file mode 100644 index 000000000000..3865d2149f42 --- /dev/null +++ b/core/res/res/anim/activity_open_exit_legacy.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?><!-- +/* +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false"> + + <!-- Fade out, over a black surface, which simulates a black scrim --> + <alpha + android:fromAlpha="1" + android:toAlpha="0.4" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/linear" + android:startOffset="83" + android:duration="167"/> + + <scale + android:fromXScale="1" + android:toXScale="1.05" + android:fromYScale="1" + android:toYScale="1.05" + android:pivotX="50%" + android:pivotY="50%" + android:fillEnabled="true" + android:fillBefore="true" + android:fillAfter="true" + android:interpolator="@interpolator/fast_out_extra_slow_in" + android:duration="400"/> +</set>
\ No newline at end of file diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 44c551259375..323c72667c33 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -673,6 +673,9 @@ <item type="dimen" format="float" name="lock_pattern_dot_hit_factor">0.6</item> <!-- Width of a gradient applied to a lock pattern line while its disappearing animation. --> <dimen name="lock_pattern_fade_away_gradient_width">8dp</dimen> + <!-- Parameters applied to line disappearing animation in LockPatternView in milliseconds. --> + <integer name="lock_pattern_line_fade_out_duration">500</integer> + <integer name="lock_pattern_line_fade_out_delay">150</integer> <dimen name="text_handle_min_size">40dp</dimen> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index ffcadd06899d..aaf6a41e996d 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -128,6 +128,7 @@ <public name="localeConfig" /> <public name="showBackground" /> <public name="useTargetActivityForQuickAccess"/> + <public name="removed_inheritKeyStoreKeys" /> <public name="preferKeepClear" /> <public name="autoHandwritingEnabled" /> <public name="fromExtendLeft" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 4a2c9119b745..f11fd92c20c2 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4091,21 +4091,6 @@ <!-- Description of an application permission that lets it query all other packages. [CHAR LIMIT=NONE] --> <string name="permdesc_queryAllPackages">Allows an app to see all installed packages.</string> - <!-- Title of an application permission that lets it access AdServices Topics API. [CHAR LIMIT=NONE] --> - <string name="permlab_accessAdServicesTopics">access AdServices Topics API</string> - <!-- Description of an application permission that lets it access AdServices Topics API. [CHAR LIMIT=NONE]--> - <string name="permdesc_accessAdServicesTopics">Allows an application to access AdServices Topics API.</string> - - <!-- Title of an application permission that lets it access AdServices Attribution APIs. [CHAR LIMIT=NONE] --> - <string name="permlab_accessAdServicesAttribution">access AdServices Attribution APIs</string> - <!-- Description of an application permission that lets it access AdServices Attribution APIs. [CHAR LIMIT=NONE]--> - <string name="permdesc_accessAdServicesAttribution">Allows an application to access AdServices Attribution APIs.</string> - - <!-- Title of an application permission that lets it access AdServices Custom Audiences API. [CHAR LIMIT=NONE] --> - <string name="permlab_accessAdServicesCustomAudiences">access AdServices Custom Audiences API</string> - <!-- Description of an application permission that lets it access AdServices Custom Audiences API. [CHAR LIMIT=NONE]--> - <string name="permdesc_accessAdServicesCustomAudiences">Allows an application to access AdServices Custom Audiences API.</string> - <!-- Shown in the tutorial for tap twice for zoom control. --> <string name="tutorial_double_tap_to_zoom_message_short">Tap twice for zoom control</string> @@ -5479,6 +5464,8 @@ <!-- Title of the dialog shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] --> <string name="app_streaming_blocked_title"><xliff:g id="activity" example="Permission dialog">%1$s</xliff:g> unavailable</string> + <!-- Title of the dialog shown when the permissioncontroller is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] --> + <string name="app_streaming_blocked_title_for_permission_dialog">Permission needed</string> <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] --> <string name="app_streaming_blocked_message" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your Android TV device instead.</string> <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] --> @@ -6292,7 +6279,9 @@ ul.</string> <!-- Strings for VirtualDeviceManager --> <!-- Error message indicating the camera cannot be accessed when running on a virtual device. [CHAR LIMIT=NONE] --> - <string name="vdm_camera_access_denied">Cannot access camera from this device</string> + <string name="vdm_camera_access_denied" product="default">Can’t access the phone’s camera from your <xliff:g id="device" example="Chromebook">%1$s</xliff:g></string> + <!-- Error message indicating the camera cannot be accessed when running on a virtual device. [CHAR LIMIT=NONE] --> + <string name="vdm_camera_access_denied" product="tablet">Can’t access the tablet’s camera from your <xliff:g id="device" example="Chromebook">%1$s</xliff:g></string> <!-- Title for preference of the system default locale. [CHAR LIMIT=50]--> <string name="system_locale_title">System language</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 845de8a3492e..f1a8e56cc8c3 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1327,6 +1327,8 @@ <java-symbol type="dimen" name="lock_pattern_dot_size_activated" /> <java-symbol type="dimen" name="lock_pattern_dot_hit_factor" /> <java-symbol type="dimen" name="lock_pattern_fade_away_gradient_width" /> + <java-symbol type="integer" name="lock_pattern_line_fade_out_duration" /> + <java-symbol type="integer" name="lock_pattern_line_fade_out_delay" /> <java-symbol type="drawable" name="clock_dial" /> <java-symbol type="drawable" name="clock_hand_hour" /> <java-symbol type="drawable" name="clock_hand_minute" /> @@ -1713,6 +1715,10 @@ <java-symbol type="anim" name="activity_open_exit" /> <java-symbol type="anim" name="activity_close_enter" /> <java-symbol type="anim" name="activity_close_exit" /> + <java-symbol type="anim" name="activity_open_enter_legacy" /> + <java-symbol type="anim" name="activity_open_exit_legacy" /> + <java-symbol type="anim" name="activity_close_enter_legacy" /> + <java-symbol type="anim" name="activity_close_exit_legacy" /> <java-symbol type="anim" name="task_fragment_close_enter" /> <java-symbol type="anim" name="task_fragment_close_exit" /> <java-symbol type="anim" name="task_fragment_open_enter" /> @@ -3294,6 +3300,7 @@ <java-symbol type="string" name="app_blocked_message" /> <java-symbol type="string" name="app_streaming_blocked_title" /> + <java-symbol type="string" name="app_streaming_blocked_title_for_permission_dialog" /> <java-symbol type="string" name="app_streaming_blocked_message" /> <!-- Used internally for assistant to launch activity transitions --> diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java index 1f6b57e5d615..a663095aa893 100644 --- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java @@ -44,7 +44,6 @@ import android.content.pm.UserInfo; import android.metrics.LogMaker; import android.net.Uri; import android.os.Bundle; -import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -649,7 +648,7 @@ public class IntentForwarderActivityTest { @Override public void startActivityAsCaller(Intent intent, @Nullable Bundle options, - IBinder permissionToken, boolean ignoreTargetSecurity, int userId) { + boolean ignoreTargetSecurity, int userId) { mStartActivityIntent = intent; mUserIdActivityLaunchedIn = userId; } diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java index dbe1e8132e1d..87c45dccfa0c 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java @@ -32,12 +32,15 @@ import static org.mockito.Mockito.mock; import android.app.ActivityManager; import android.app.usage.NetworkStatsManager; +import android.hardware.radio.V1_5.AccessNetwork; import android.os.BatteryStats; import android.os.BatteryStats.HistoryItem; import android.os.BatteryStats.Uid.Sensor; import android.os.Process; import android.os.UserHandle; import android.os.WorkSource; +import android.telephony.AccessNetworkConstants; +import android.telephony.ActivityStatsTechSpecificInfo; import android.telephony.Annotation; import android.telephony.CellSignalStrength; import android.telephony.DataConnectionRealTimeInfo; @@ -58,8 +61,10 @@ import junit.framework.TestCase; import org.mockito.Mock; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.IntConsumer; @@ -1322,7 +1327,7 @@ public class BatteryStatsNoteTest extends TestCase { } } - final ModemAndBatteryState state = new ModemAndBatteryState(bi, null); + final ModemAndBatteryState state = new ModemAndBatteryState(bi, null, null); IntConsumer incrementTime = inc -> { state.currentTimeMs += inc; @@ -1469,32 +1474,16 @@ public class BatteryStatsNoteTest extends TestCase { final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount]; for (int rat = 0; rat < ratCount; rat++) { for (int freq = 0; freq < frequencyCount; freq++) { - if (rat != RADIO_ACCESS_TECHNOLOGY_NR - && freq != ServiceState.FREQUENCY_RANGE_UNKNOWN) { - // Only the NR RAT should have per frequency data. - expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE; - } else { - expectedRxDurationsMs[rat][freq] = 0; - } expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE; for (int txLvl = 0; txLvl < txLevelCount; txLvl++) { - expectedDurationsMs[rat][freq][txLvl] = 0; - - if (rat != RADIO_ACCESS_TECHNOLOGY_NR - && freq != ServiceState.FREQUENCY_RANGE_UNKNOWN) { - // Only the NR RAT should have per frequency data. - expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE; - } else { - expectedTxDurationsMs[rat][freq][txLvl] = 0; - } expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE; } } } final ModemActivityInfo mai = new ModemActivityInfo(0L, 0L, 0L, new int[txLevelCount], 0L); - final ModemAndBatteryState state = new ModemAndBatteryState(bi, mai); + final ModemAndBatteryState state = new ModemAndBatteryState(bi, mai, null); IntConsumer incrementTime = inc -> { state.currentTimeMs += inc; @@ -1711,6 +1700,288 @@ public class BatteryStatsNoteTest extends TestCase { expectedTxDurationsMs, bi, state.currentTimeMs); } + @SmallTest + public void testGetPerStateActiveRadioDurationMs_withSpecificInfoModemActivity() { + final MockClock clock = new MockClock(); // holds realtime and uptime in ms + final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock); + bi.setPowerProfile(mock(PowerProfile.class)); + final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT; + final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1; + final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels(); + + List<ActivityStatsTechSpecificInfo> specificInfoList = new ArrayList(); + + final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount]; + final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount]; + final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount]; + for (int rat = 0; rat < ratCount; rat++) { + for (int freq = 0; freq < frequencyCount; freq++) { + if (rat == RADIO_ACCESS_TECHNOLOGY_NR + || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) { + // Initialize available specific Modem info + specificInfoList.add( + new ActivityStatsTechSpecificInfo(rat, freq, new int[txLevelCount], 0)); + } + expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE; + + for (int txLvl = 0; txLvl < txLevelCount; txLvl++) { + expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE; + } + } + } + + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.UNKNOWN, + ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.GERAN, + ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.UTRAN, + ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.EUTRAN, + ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.CDMA2000, + ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.IWLAN, + ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN, + ServiceState.FREQUENCY_RANGE_UNKNOWN, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN, + ServiceState.FREQUENCY_RANGE_LOW, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN, + ServiceState.FREQUENCY_RANGE_MID, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN, + ServiceState.FREQUENCY_RANGE_HIGH, new int[txLevelCount], 0)); + specificInfoList.add(new ActivityStatsTechSpecificInfo(AccessNetwork.NGRAN, + ServiceState.FREQUENCY_RANGE_MMWAVE, new int[txLevelCount], 0)); + + final ActivityStatsTechSpecificInfo[] specificInfos = specificInfoList.toArray( + new ActivityStatsTechSpecificInfo[specificInfoList.size()]); + final ModemActivityInfo mai = new ModemActivityInfo(0L, 0L, 0L, specificInfos); + final ModemAndBatteryState state = new ModemAndBatteryState(bi, mai, specificInfos); + + IntConsumer incrementTime = inc -> { + state.currentTimeMs += inc; + clock.realtime = clock.uptime = state.currentTimeMs; + + // If the device is not on battery, no timers should increment. + if (!state.onBattery) return; + // If the modem is not active, no timers should increment. + if (!state.modemActive) return; + + final int currRat = state.currentRat; + final int currRant = state.currentRadioAccessNetworkType; + final int currFreqRange = + currRat == RADIO_ACCESS_TECHNOLOGY_NR ? state.currentFrequencyRange : 0; + int currSignalStrength = state.currentSignalStrengths.get(currRat); + + expectedDurationsMs[currRat][currFreqRange][currSignalStrength] += inc; + + // Evaluate the HAL provided time in states. + final ActivityStatsTechSpecificInfo info = state.getSpecificInfo(currRant, + currFreqRange); + switch (state.modemState) { + case SLEEP: + long sleepMs = state.modemActivityInfo.getSleepTimeMillis(); + state.modemActivityInfo.setSleepTimeMillis(sleepMs + inc); + break; + case IDLE: + long idleMs = state.modemActivityInfo.getIdleTimeMillis(); + state.modemActivityInfo.setIdleTimeMillis(idleMs + inc); + break; + case RECEIVING: + long rxMs = info.getReceiveTimeMillis(); + info.setReceiveTimeMillis(rxMs + inc); + expectedRxDurationsMs[currRat][currFreqRange] += inc; + break; + case TRANSMITTING: + int[] txMs = info.getTransmitTimeMillis().clone(); + txMs[currSignalStrength] += inc; + info.setTransmitTimeMillis(txMs); + expectedTxDurationsMs[currRat][currFreqRange][currSignalStrength] += inc; + break; + } + }; + + state.setOnBattery(false); + state.setModemActive(false); + state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN, + BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER, + AccessNetworkConstants.AccessNetworkType.UNKNOWN); + state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN); + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER, + CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // While not on battery, the timers should not increase. + state.setModemActive(true); + incrementTime.accept(100); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR, + AccessNetworkConstants.AccessNetworkType.NGRAN); + incrementTime.accept(200); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR, + CellSignalStrength.SIGNAL_STRENGTH_GOOD); + incrementTime.accept(500); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE); + incrementTime.accept(300); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setRatType(TelephonyManager.NETWORK_TYPE_LTE, + BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE, + AccessNetworkConstants.AccessNetworkType.EUTRAN); + incrementTime.accept(400); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE, + CellSignalStrength.SIGNAL_STRENGTH_MODERATE); + incrementTime.accept(500); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // Data will now be available. + for (int rat = 0; rat < ratCount; rat++) { + for (int freq = 0; freq < frequencyCount; freq++) { + if (rat == RADIO_ACCESS_TECHNOLOGY_NR + || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) { + // Only the NR RAT should have per frequency data. + expectedRxDurationsMs[rat][freq] = 0; + } + for (int txLvl = 0; txLvl < txLevelCount; txLvl++) { + if (rat == RADIO_ACCESS_TECHNOLOGY_NR + || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) { + // Only the NR RAT should have per frequency data. + expectedTxDurationsMs[rat][freq][txLvl] = 0; + } + } + } + } + + // When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should + // start counting up. + state.setOnBattery(true); + state.noteModemControllerActivity(); + incrementTime.accept(300); + state.setModemState(ModemState.RECEIVING); + incrementTime.accept(500); + state.setModemState(ModemState.TRANSMITTING); + incrementTime.accept(600); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + // Changing LTE signal strength should be tracked. + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE, + CellSignalStrength.SIGNAL_STRENGTH_POOR); + incrementTime.accept(300); + state.setModemState(ModemState.SLEEP); + incrementTime.accept(1000); + state.setModemState(ModemState.RECEIVING); + incrementTime.accept(700); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE, + CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN); + incrementTime.accept(800); + state.setModemState(ModemState.TRANSMITTING); + incrementTime.accept(222); + state.setModemState(ModemState.IDLE); + incrementTime.accept(111); + state.setModemState(ModemState.RECEIVING); + incrementTime.accept(7777); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE, + CellSignalStrength.SIGNAL_STRENGTH_GOOD); + incrementTime.accept(88); + state.setModemState(ModemState.TRANSMITTING); + incrementTime.accept(900); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE, + CellSignalStrength.SIGNAL_STRENGTH_GREAT); + incrementTime.accept(123); + state.setModemState(ModemState.RECEIVING); + incrementTime.accept(333); + state.setModemState(ModemState.TRANSMITTING); + incrementTime.accept(1000); + state.setModemState(ModemState.RECEIVING); + incrementTime.accept(555); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // Change in the signal strength of nonactive RAT should not affect anything. + state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER, + CellSignalStrength.SIGNAL_STRENGTH_POOR); + incrementTime.accept(631); + state.setModemState(ModemState.TRANSMITTING); + incrementTime.accept(321); + state.setModemState(ModemState.RECEIVING); + incrementTime.accept(99); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // Changing to OTHER Rat should start tracking the poor signal strength. + state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA, + BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER, + AccessNetworkConstants.AccessNetworkType.CDMA2000); + incrementTime.accept(1200); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // Noting frequency change should not affect non NR Rat. + state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH); + incrementTime.accept(444); + state.setModemState(ModemState.TRANSMITTING); + incrementTime.accept(1300); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // Now the NR Rat, HIGH frequency range, good signal strength should start counting. + state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR, + AccessNetworkConstants.AccessNetworkType.NGRAN); + incrementTime.accept(1400); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // Frequency changed to low. + state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW); + incrementTime.accept(852); + state.setModemState(ModemState.RECEIVING); + incrementTime.accept(157); + state.setModemState(ModemState.TRANSMITTING); + incrementTime.accept(1500); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + + // Modem no longer active, should not be tracking any more. + state.setModemActive(false); + incrementTime.accept(1500); + state.noteModemControllerActivity(); + checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs, + expectedTxDurationsMs, bi, state.currentTimeMs); + } + private void setFgState(int uid, boolean fgOn, MockBatteryStatsImpl bi) { // Note that noteUidProcessStateLocked uses ActivityManager process states. if (fgOn) { @@ -1841,17 +2112,22 @@ public class BatteryStatsNoteTest extends TestCase { public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN; @BatteryStats.RadioAccessTechnology public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER; + @AccessNetworkConstants.RadioAccessNetworkType + public int currentRadioAccessNetworkType = AccessNetworkConstants.AccessNetworkType.UNKNOWN; @ServiceState.FrequencyRange public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN; public SparseIntArray currentSignalStrengths = new SparseIntArray(); public ModemState modemState = ModemState.SLEEP; public ModemActivityInfo modemActivityInfo; + public ActivityStatsTechSpecificInfo[] specificInfo; private final MockBatteryStatsImpl mBsi; - ModemAndBatteryState(MockBatteryStatsImpl bsi, ModemActivityInfo mai) { + ModemAndBatteryState(MockBatteryStatsImpl bsi, ModemActivityInfo mai, + ActivityStatsTechSpecificInfo[] astsi) { mBsi = bsi; modemActivityInfo = mai; + specificInfo = astsi; } void setOnBattery(boolean onBattery) { @@ -1871,6 +2147,13 @@ public class BatteryStatsNoteTest extends TestCase { } void setRatType(@Annotation.NetworkType int dataType, + @BatteryStats.RadioAccessTechnology int rat, + @AccessNetworkConstants.RadioAccessNetworkType int halDataType) { + currentRadioAccessNetworkType = halDataType; + setRatType(dataType, rat); + } + + void setRatType(@Annotation.NetworkType int dataType, @BatteryStats.RadioAccessTechnology int rat) { currentNetworkDataType = dataType; currentRat = rat; @@ -1895,13 +2178,45 @@ public class BatteryStatsNoteTest extends TestCase { modemState = state; } + ActivityStatsTechSpecificInfo getSpecificInfo(@BatteryStats.RadioAccessTechnology int rat, + @ServiceState.FrequencyRange int frequency) { + if (specificInfo == null) return null; + for (ActivityStatsTechSpecificInfo info : specificInfo) { + if (info.getRat() == rat && info.getFrequencyRange() == frequency) { + return info; + } + } + return null; + } + void noteModemControllerActivity() { if (modemActivityInfo == null) return; modemActivityInfo.setTimestamp(currentTimeMs); - ModemActivityInfo copy = new ModemActivityInfo(modemActivityInfo.getTimestampMillis(), - modemActivityInfo.getSleepTimeMillis(), modemActivityInfo.getIdleTimeMillis(), - modemActivityInfo.getTransmitTimeMillis().clone(), - modemActivityInfo.getReceiveTimeMillis()); + final ModemActivityInfo copy; + if (specificInfo == null) { + copy = new ModemActivityInfo( + modemActivityInfo.getTimestampMillis(), + modemActivityInfo.getSleepTimeMillis(), + modemActivityInfo.getIdleTimeMillis(), + modemActivityInfo.getTransmitTimeMillis().clone(), + modemActivityInfo.getReceiveTimeMillis()); + } else { + // Deep copy specificInfo + final ActivityStatsTechSpecificInfo[] infoCopies = + new ActivityStatsTechSpecificInfo[specificInfo.length]; + for (int i = 0; i < specificInfo.length; i++) { + final ActivityStatsTechSpecificInfo info = specificInfo[i]; + infoCopies[i] = new ActivityStatsTechSpecificInfo(info.getRat(), + info.getFrequencyRange(), info.getTransmitTimeMillis().clone(), + (int) info.getReceiveTimeMillis()); + } + + copy = new ModemActivityInfo( + modemActivityInfo.getTimestampMillis(), + modemActivityInfo.getSleepTimeMillis(), + modemActivityInfo.getIdleTimeMillis(), + infoCopies); + } mBsi.noteModemControllerActivity(copy, POWER_DATA_UNAVAILABLE, currentTimeMs, currentTimeMs, mNetworkStatsManager); } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index bde18f36684c..6b66fadde020 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -613,12 +613,6 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityStarter.java" }, - "-1488852351": { - "message": "Task=%d contains embedded TaskFragment in untrusted mode. Disabled all input during TaskFragment remote animation.", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, "-1483435730": { "message": "InsetsSource setWin %s for type %s", "level": "DEBUG", @@ -3439,12 +3433,6 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1333520287": { - "message": "Creating PendingTransition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, "1335791109": { "message": "createSurface %s: mDrawState=DRAW_PENDING", "level": "INFO", @@ -3739,6 +3727,12 @@ "group": "WM_DEBUG_IME", "at": "com\/android\/server\/wm\/InsetsStateController.java" }, + "1667162379": { + "message": "Creating Pending Transition: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" + }, "1670933628": { "message": " Setting allReady override", "level": "VERBOSE", @@ -3793,6 +3787,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1730300180": { + "message": "PendingStartTransaction found", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + }, "1739298851": { "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d", "level": "WARN", @@ -4105,12 +4105,6 @@ "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "2034988903": { - "message": "PendingStartTransaction found", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, "2039056415": { "message": "Found matching affinity candidate!", "level": "DEBUG", @@ -4165,6 +4159,12 @@ "group": "WM_DEBUG_KEEP_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "2100457473": { + "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.", + "level": "DEBUG", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, "2114149926": { "message": "Not removing %s because app died while it's visible", "level": "VERBOSE", diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index bd0e56a39e03..c81473ddcfc6 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -416,6 +416,8 @@ key usage 0x0c0067 WINDOW key usage 0x0c006F BRIGHTNESS_UP key usage 0x0c0070 BRIGHTNESS_DOWN key usage 0x0c0173 MEDIA_AUDIO_TRACK +key usage 0x0c019C PROFILE_SWITCH +key usage 0x0c01A2 ALL_APPS # Joystick and game controller axes. # Axes that are not mapped will be assigned generic axis numbers by the input subsystem. diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl index 672abef3c963..13b4096ca82a 100644 --- a/data/keyboards/Vendor_0957_Product_0001.kl +++ b/data/keyboards/Vendor_0957_Product_0001.kl @@ -44,6 +44,8 @@ key 10 9 key 11 0 # custom keys +key usage 0x000c019C PROFILE_SWITCH +key usage 0x000c01A2 ALL_APPS key usage 0x000c01BB TV_INPUT key usage 0x000c022A BOOKMARK key usage 0x000c0096 SETTINGS @@ -53,6 +55,7 @@ key usage 0x000c0089 TV key usage 0x000c009C CHANNEL_UP key usage 0x000c009D CHANNEL_DOWN key usage 0x000c00CD MEDIA_PLAY_PAUSE +key usage 0x000c00B2 MEDIA_RECORD key usage 0x000c00B4 MEDIA_SKIP_BACKWARD key usage 0x000c00B3 MEDIA_SKIP_FORWARD key usage 0x000c0226 MEDIA_STOP @@ -62,6 +65,7 @@ key usage 0x000c0078 BUTTON_4 WAKE #Netflix key usage 0x000c0079 BUTTON_6 WAKE #Disney+ key usage 0x000c007A BUTTON_7 WAKE #HBOmax +key usage 0x00070037 PERIOD key usage 0x000c01BD INFO key usage 0x000c0061 CAPTIONS key usage 0x000c0185 TV_TELETEXT diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index 61dc136e8d65..7cc22d753f69 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -984,12 +984,12 @@ public class HardwareRenderer { } /** - * b/68769804: For low FPS experiments. + * b/68769804, b/66945974: For low FPS experiments. * * @hide */ public static void setFPSDivisor(int divisor) { - nHackySetRTAnimationsEnabled(divisor <= 1); + nSetRtAnimationsEnabled(divisor <= 1); } /** @@ -1153,6 +1153,16 @@ public class HardwareRenderer { nSetDrawingEnabled(drawingEnabled); } + /** + * Disable RenderThread animations that schedule draws directly from RenderThread. This is used + * when we don't want to de-schedule draw requests that come from the UI thread. + * + * @hide + */ + public static void setRtAnimationsEnabled(boolean enabled) { + nSetRtAnimationsEnabled(enabled); + } + private static final class DestroyContextRunnable implements Runnable { private final long mNativeInstance; @@ -1461,9 +1471,6 @@ public class HardwareRenderer { private static native void nSetHighContrastText(boolean enabled); - // For temporary experimentation b/66945974 - private static native void nHackySetRTAnimationsEnabled(boolean enabled); - private static native void nSetDebuggingEnabled(boolean enabled); private static native void nSetIsolatedProcess(boolean enabled); @@ -1482,4 +1489,6 @@ public class HardwareRenderer { private static native void nSetDrawingEnabled(boolean drawingEnabled); private static native boolean nIsDrawingEnabled(); + + private static native void nSetRtAnimationsEnabled(boolean rtAnimationsEnabled); } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java index 1c49881904e4..921552b6cfbb 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java @@ -236,7 +236,8 @@ public final class CommonFoldingFeature { } private static void assertValidState(@Nullable Integer state) { - if (state != null && state != COMMON_STATE_FLAT && state != COMMON_STATE_HALF_OPENED) { + if (state != null && state != COMMON_STATE_FLAT + && state != COMMON_STATE_HALF_OPENED && state != COMMON_STATE_UNKNOWN) { throw new IllegalArgumentException("Invalid state: " + state + "must be either COMMON_STATE_FLAT or COMMON_STATE_HALF_OPENED"); } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java index e9d213e06fa9..0e696eb8efb7 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/SettingsDisplayFeatureProducer.java @@ -16,6 +16,8 @@ package androidx.window.common; +import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_FLAT; +import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_HALF_OPENED; import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN; import static androidx.window.common.CommonFoldingFeature.parseListFromString; @@ -42,7 +44,10 @@ import java.util.Optional; public final class SettingsDisplayFeatureProducer extends BaseDataProducer<List<CommonFoldingFeature>> { private static final String DISPLAY_FEATURES = "display_features"; + private static final String DEVICE_POSTURE = "device_posture"; + private final Uri mDevicePostureUri = + Settings.Global.getUriFor(DEVICE_POSTURE); private final Uri mDisplayFeaturesUri = Settings.Global.getUriFor(DISPLAY_FEATURES); @@ -55,6 +60,15 @@ public final class SettingsDisplayFeatureProducer mObserver = new SettingsObserver(); } + private int getPosture() { + int posture = Settings.Global.getInt(mResolver, DEVICE_POSTURE, COMMON_STATE_UNKNOWN); + if (posture == COMMON_STATE_HALF_OPENED || posture == COMMON_STATE_FLAT) { + return posture; + } else { + return COMMON_STATE_UNKNOWN; + } + } + @Override @NonNull public Optional<List<CommonFoldingFeature>> getData() { @@ -66,7 +80,7 @@ public final class SettingsDisplayFeatureProducer if (TextUtils.isEmpty(displayFeaturesString)) { return Optional.of(Collections.emptyList()); } - return Optional.of(parseListFromString(displayFeaturesString, COMMON_STATE_UNKNOWN)); + return Optional.of(parseListFromString(displayFeaturesString, getPosture())); } /** @@ -80,6 +94,7 @@ public final class SettingsDisplayFeatureProducer mRegisteredObservers = true; mResolver.registerContentObserver(mDisplayFeaturesUri, false /* notifyForDescendants */, mObserver /* ContentObserver */); + mResolver.registerContentObserver(mDevicePostureUri, false, mObserver); } /** @@ -101,7 +116,7 @@ public final class SettingsDisplayFeatureProducer @Override public void onChange(boolean selfChange, Uri uri) { - if (mDisplayFeaturesUri.equals(uri)) { + if (mDisplayFeaturesUri.equals(uri) || mDevicePostureUri.equals(uri)) { notifyDataChanged(); } } diff --git a/libs/WindowManager/Jetpack/tests/OWNERS b/libs/WindowManager/Jetpack/tests/OWNERS new file mode 100644 index 000000000000..f2c3388023be --- /dev/null +++ b/libs/WindowManager/Jetpack/tests/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 909476 +# includes OWNERS from parent directories +charlesccchen@google.com +diegovela@google.com diff --git a/libs/WindowManager/Jetpack/tests/unittest/Android.bp b/libs/WindowManager/Jetpack/tests/unittest/Android.bp new file mode 100644 index 000000000000..62e8128f9362 --- /dev/null +++ b/libs/WindowManager/Jetpack/tests/unittest/Android.bp @@ -0,0 +1,52 @@ +// Copyright (C) 2022 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "WMJetpackUnitTests", + + srcs: [ + "**/*.java", + ], + + static_libs: [ + "androidx.window.extensions", + "junit", + "androidx.test.runner", + "androidx.test.rules", + "androidx.test.ext.junit", + "mockito-target-extended-minus-junit4", + "truth-prebuilt", + "testables", + "platform-test-annotations", + ], + + libs: [ + "android.test.mock", + "android.test.base", + "android.test.runner", + ], + + optimize: { + enabled: false, + }, +} diff --git a/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml new file mode 100644 index 000000000000..b12b6f6f0ef1 --- /dev/null +++ b/libs/WindowManager/Jetpack/tests/unittest/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="androidx.window.tests"> + + <application android:debuggable="true" android:largeHeap="true"> + <uses-library android:name="android.test.mock" /> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:label="Tests for WindowManager Jetpack library" + android:targetPackage="androidx.window.tests"> + </instrumentation> +</manifest> diff --git a/libs/WindowManager/Jetpack/tests/unittest/AndroidTest.xml b/libs/WindowManager/Jetpack/tests/unittest/AndroidTest.xml new file mode 100644 index 000000000000..56d8c33fdc09 --- /dev/null +++ b/libs/WindowManager/Jetpack/tests/unittest/AndroidTest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Runs Tests for WindowManager Jetpack library"> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="install-arg" value="-t" /> + <option name="test-file-name" value="WMJetpackUnitTests.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="framework-base-presubmit" /> + <option name="test-tag" value="WMJetpackUnitTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="androidx.window.tests" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration> diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java new file mode 100644 index 000000000000..b6df876e1956 --- /dev/null +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.window.extensions; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class WindowExtensionsTest { + private WindowExtensions mExtensions; + + @Before + public void setUp() { + mExtensions = WindowExtensionsProvider.getWindowExtensions(); + } + + @Test + public void testGetWindowLayoutComponent() { + assertThat(mExtensions.getWindowLayoutComponent()).isNotNull(); + } + + @Test + public void testGetActivityEmbeddingComponent() { + assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull(); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index da8308ee7bab..10ff2fb31b0d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -692,6 +692,7 @@ public class BubbleExpandedView extends LinearLayout { * @param bubblePosition the x position of the bubble if showing on top, the y position of * the bubble if showing vertically. * @param onLeft whether the stack was on the left side of the screen when expanded. + * @param animate whether the pointer should animate to this position. */ public void setPointerPosition(float bubblePosition, boolean onLeft, boolean animate) { // Pointer gets drawn in the padding diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 8a120b94f96d..97e5ee3a35d3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -579,11 +579,10 @@ public class BubblePositioner { // Showing vertically: might need to translate the bubbles above the IME. // Subtract spacing here to provide a margin between top of IME and bottom of bubble row. - final float bottomInset = getImeHeight() + mInsets.bottom - (mSpacingBetweenBubbles * 2); + final float bottomHeight = getImeHeight() + mInsets.bottom - (mSpacingBetweenBubbles * 2); + final float bottomInset = mScreenRect.bottom - bottomHeight; final float expandedStackSize = getExpandedStackSize(numberOfBubbles); - final float centerPosition = showBubblesVertically() - ? mPositionRect.centerY() - : mPositionRect.centerX(); + final float centerPosition = mPositionRect.centerY(); final float rowBottom = centerPosition + (expandedStackSize / 2f); final float rowTop = centerPosition - (expandedStackSize / 2f); float rowTopForIme = rowTop; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl index b4c745fc4892..ef627647794e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl @@ -32,4 +32,9 @@ oneway interface IPipAnimationListener { * @param cornerRadius the pixel value of the corner radius, zero means it's disabled. */ void onPipCornerRadiusChanged(int cornerRadius); + + /** + * Notifies the listener that user leaves PiP by tapping on the expand button. + */ + void onExpandPip(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 9b0476411370..ad5d85cc083a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -96,7 +96,7 @@ import java.util.function.Consumer; * Manages the picture-in-picture (PIP) UI and states for Phones. */ public class PipController implements PipTransitionController.PipTransitionCallback, - RemoteCallable<PipController>, DisplayController.OnDisplaysChangedListener { + RemoteCallable<PipController> { private static final String TAG = "PipController"; private Context mContext; @@ -137,6 +137,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb * @param cornerRadius the pixel value of the corner radius, zero means it's disabled. */ void onPipCornerRadiusChanged(int cornerRadius); + + /** + * Notifies the listener that user leaves PiP by tapping on the expand button. + */ + void onExpandPip(); } /** @@ -229,6 +234,14 @@ public class PipController implements PipTransitionController.PipTransitionCallb onDisplayChanged(mDisplayController.getDisplayLayout(displayId), true /* saveRestoreSnapFraction */); } + + @Override + public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted, + Set<Rect> unrestricted) { + if (mPipBoundsState.getDisplayId() == displayId) { + mPipBoundsState.setKeepClearAreas(restricted, unrestricted); + } + } }; /** @@ -458,14 +471,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb return mMainExecutor; } - @Override - public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted, - Set<Rect> unrestricted) { - if (mPipBoundsState.getDisplayId() == displayId) { - mPipBoundsState.setKeepClearAreas(restricted, unrestricted); - } - } - private void onConfigurationChanged(Configuration newConfig) { mPipBoundsAlgorithm.onConfigurationChanged(mContext); mTouchHandler.onConfigurationChanged(); @@ -652,6 +657,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb mTouchHandler.setTouchEnabled(false); if (mPinnedStackAnimationRecentsCallback != null) { mPinnedStackAnimationRecentsCallback.onPipAnimationStarted(); + if (direction == TRANSITION_DIRECTION_LEAVE_PIP) { + mPinnedStackAnimationRecentsCallback.onExpandPip(); + } } } @@ -911,6 +919,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb public void onPipCornerRadiusChanged(int cornerRadius) { mListener.call(l -> l.onPipCornerRadiusChanged(cornerRadius)); } + + @Override + public void onExpandPip() { + mListener.call(l -> l.onExpandPip()); + } }; IPipImpl(PipController controller) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index af6e5d4c6f1a..aef298ed478a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -217,7 +217,8 @@ public class PipControllerTest extends ShellTestCase { final Rect keepClearArea = new Rect(0, 0, 10, 10); when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId); - mPipController.onKeepClearAreasChanged(displayId, Set.of(keepClearArea), Set.of()); + mPipController.mDisplaysChangedListener.onKeepClearAreasChanged( + displayId, Set.of(keepClearArea), Set.of()); verify(mMockPipBoundsState).setKeepClearAreas(Set.of(keepClearArea), Set.of()); } diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 7a8ddfba949b..c48448dffdd2 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -777,11 +777,6 @@ static void android_view_ThreadedRenderer_setHighContrastText(JNIEnv*, jclass, j Properties::enableHighContrastText = enable; } -static void android_view_ThreadedRenderer_hackySetRTAnimationsEnabled(JNIEnv*, jclass, - jboolean enable) { - Properties::enableRTAnimations = enable; -} - static void android_view_ThreadedRenderer_setDebuggingEnabled(JNIEnv*, jclass, jboolean enable) { Properties::debuggingEnabled = enable; } @@ -811,6 +806,11 @@ static void android_view_ThreadedRenderer_preload(JNIEnv*, jclass) { RenderProxy::preload(); } +static void android_view_ThreadedRenderer_setRtAnimationsEnabled(JNIEnv* env, jobject clazz, + jboolean enabled) { + RenderProxy::setRtAnimationsEnabled(enabled); +} + // Plumbs the display density down to DeviceInfo. static void android_view_ThreadedRenderer_setDisplayDensityDpi(JNIEnv*, jclass, jint densityDpi) { // Convert from dpi to density-independent pixels. @@ -967,8 +967,6 @@ static const JNINativeMethod gMethods[] = { (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode}, {"disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync}, {"nSetHighContrastText", "(Z)V", (void*)android_view_ThreadedRenderer_setHighContrastText}, - {"nHackySetRTAnimationsEnabled", "(Z)V", - (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled}, {"nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled}, {"nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess}, {"nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority}, @@ -982,6 +980,8 @@ static const JNINativeMethod gMethods[] = { (void*)android_view_ThreadedRenderer_isWebViewOverlaysEnabled}, {"nSetDrawingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDrawingEnabled}, {"nIsDrawingEnabled", "()Z", (void*)android_view_ThreadedRenderer_isDrawingEnabled}, + {"nSetRtAnimationsEnabled", "(Z)V", + (void*)android_view_ThreadedRenderer_setRtAnimationsEnabled}, }; static JavaVM* mJvm = nullptr; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 57ef4f4f8f60..a44b498c81c1 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -428,6 +428,15 @@ void RenderProxy::preload() { thread.queue().post([&thread]() { thread.preload(); }); } +void RenderProxy::setRtAnimationsEnabled(bool enabled) { + if (RenderThread::hasInstance()) { + RenderThread::getInstance().queue().post( + [enabled]() { Properties::enableRTAnimations = enabled; }); + } else { + Properties::enableRTAnimations = enabled; + } +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 0f5a41cfbe38..ee9efd46e307 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -144,6 +144,8 @@ public: static void preload(); + static void setRtAnimationsEnabled(bool enabled); + private: RenderThread& mRenderThread; CanvasContext* mContext; diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java index 71042412e546..11cacd01f53d 100644 --- a/media/java/android/media/AudioDeviceVolumeManager.java +++ b/media/java/android/media/AudioDeviceVolumeManager.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -27,6 +28,8 @@ import android.os.ServiceManager; import com.android.internal.annotations.GuardedBy; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -40,6 +43,22 @@ public class AudioDeviceVolumeManager { // define when using Log.* //private static final String TAG = "AudioDeviceVolumeManager"; + + /** Indicates no special treatment in the handling of the volume adjustment */ + public static final int ADJUST_MODE_NORMAL = 0; + /** Indicates the start of a volume adjustment */ + public static final int ADJUST_MODE_START = 1; + /** Indicates the end of a volume adjustment */ + public static final int ADJUST_MODE_END = 2; + + @IntDef(flag = false, prefix = "ADJUST_MODE", value = { + ADJUST_MODE_NORMAL, + ADJUST_MODE_START, + ADJUST_MODE_END} + ) + @Retention(RetentionPolicy.SOURCE) + public @interface VolumeAdjustmentMode {} + private static IAudioService sService; private final String mPackageName; @@ -65,18 +84,33 @@ public class AudioDeviceVolumeManager { void onAudioDeviceVolumeChanged( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo vol); + + /** + * Called when the volume for the given audio device has been adjusted. + * @param device the audio device whose volume has been adjusted + * @param vol the volume info for the device + * @param direction the direction of the adjustment + * @param mode the volume adjustment mode + */ + void onAudioDeviceVolumeAdjusted( + @NonNull AudioDeviceAttributes device, + @NonNull VolumeInfo vol, + @AudioManager.VolumeAdjustment int direction, + @VolumeAdjustmentMode int mode); } static class ListenerInfo { final @NonNull OnAudioDeviceVolumeChangedListener mListener; final @NonNull Executor mExecutor; final @NonNull AudioDeviceAttributes mDevice; + final @NonNull boolean mHandlesVolumeAdjustment; ListenerInfo(@NonNull OnAudioDeviceVolumeChangedListener listener, @NonNull Executor exe, - @NonNull AudioDeviceAttributes device) { + @NonNull AudioDeviceAttributes device, boolean handlesVolumeAdjustment) { mListener = listener; mExecutor = exe; mDevice = device; + mHandlesVolumeAdjustment = handlesVolumeAdjustment; } } @@ -98,11 +132,12 @@ public class AudioDeviceVolumeManager { * @param device device for which volume is monitored */ public void register(boolean register, @NonNull AudioDeviceAttributes device, - @NonNull List<VolumeInfo> volumes) { + @NonNull List<VolumeInfo> volumes, boolean handlesVolumeAdjustment) { try { getService().registerDeviceVolumeDispatcherForAbsoluteVolume(register, this, mPackageName, - Objects.requireNonNull(device), Objects.requireNonNull(volumes)); + Objects.requireNonNull(device), Objects.requireNonNull(volumes), + handlesVolumeAdjustment); } catch (RemoteException e) { e.rethrowFromSystemServer(); } @@ -116,12 +151,29 @@ public class AudioDeviceVolumeManager { volumeListeners = (ArrayList<ListenerInfo>) mDeviceVolumeListeners.clone(); } for (ListenerInfo listenerInfo : volumeListeners) { - if (listenerInfo.mDevice.equals(device)) { + if (listenerInfo.mDevice.equalTypeAddress(device)) { listenerInfo.mExecutor.execute( () -> listenerInfo.mListener.onAudioDeviceVolumeChanged(device, vol)); } } } + + @Override + public void dispatchDeviceVolumeAdjusted( + @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo vol, int direction, + int mode) { + final ArrayList<ListenerInfo> volumeListeners; + synchronized (mDeviceVolumeListenerLock) { + volumeListeners = (ArrayList<ListenerInfo>) mDeviceVolumeListeners.clone(); + } + for (ListenerInfo listenerInfo : volumeListeners) { + if (listenerInfo.mDevice.equalTypeAddress(device)) { + listenerInfo.mExecutor.execute( + () -> listenerInfo.mListener.onAudioDeviceVolumeAdjusted(device, vol, + direction, mode)); + } + } + } } /** @@ -139,10 +191,12 @@ public class AudioDeviceVolumeManager { @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener, + boolean handlesVolumeAdjustment) { final ArrayList<VolumeInfo> volumes = new ArrayList<>(1); volumes.add(volume); - setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener); + setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener, + handlesVolumeAdjustment); } /** @@ -153,6 +207,9 @@ public class AudioDeviceVolumeManager { * @param volumes the list of volumes the given device responds to * @param executor the Executor used for receiving volume updates through the listener * @param vclistener the callback for volume updates + * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately + * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume} + * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}. */ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.BLUETOOTH_PRIVILEGED }) @@ -160,14 +217,15 @@ public class AudioDeviceVolumeManager { @NonNull AudioDeviceAttributes device, @NonNull List<VolumeInfo> volumes, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener, + boolean handlesVolumeAdjustment) { Objects.requireNonNull(device); Objects.requireNonNull(volumes); Objects.requireNonNull(executor); Objects.requireNonNull(vclistener); - // TODO verify not already registered - //final ListenerInfo listenerInfo = new ListenerInfo(vclistener, executor, device); + final ListenerInfo listenerInfo = new ListenerInfo( + vclistener, executor, device, handlesVolumeAdjustment); synchronized (mDeviceVolumeListenerLock) { if (mDeviceVolumeListeners == null) { mDeviceVolumeListeners = new ArrayList<>(); @@ -176,8 +234,17 @@ public class AudioDeviceVolumeManager { if (mDeviceVolumeDispatcherStub == null) { mDeviceVolumeDispatcherStub = new DeviceVolumeDispatcherStub(); } + } else { + for (ListenerInfo info : mDeviceVolumeListeners) { + if (info.mListener == vclistener) { + throw new IllegalArgumentException( + "attempt to call setDeviceAbsoluteMultiVolumeBehavior() " + + "on a previously registered listener"); + } + } } - mDeviceVolumeDispatcherStub.register(true, device, volumes); + mDeviceVolumeListeners.add(listenerInfo); + mDeviceVolumeDispatcherStub.register(true, device, volumes, handlesVolumeAdjustment); } } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 1a56b1542b07..491a5cda2950 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -604,6 +604,13 @@ public class AudioManager { @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final int FLAG_FROM_KEY = 1 << 12; + /** + * Indicates that an absolute volume controller is notifying AudioService of a change in the + * volume or mute status of an external audio system. + * @hide + */ + public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13; + /** @hide */ @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = { ENCODED_SURROUND_OUTPUT_UNKNOWN, @@ -661,6 +668,7 @@ public class AudioManager { FLAG_SHOW_UI_WARNINGS, FLAG_SHOW_VIBRATE_HINT, FLAG_FROM_KEY, + FLAG_ABSOLUTE_VOLUME, }) @Retention(RetentionPolicy.SOURCE) public @interface Flags {} @@ -682,6 +690,7 @@ public class AudioManager { FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS"); FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT"); FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY"); + FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME"); } /** @hide */ @@ -8393,6 +8402,12 @@ public class AudioManager { * {@link #addAssistantServicesUids(int[])} and not yet removed with * {@link #removeAssistantServicesUids(int[])} * + * <p> Note that during native audioserver crash and after boot up the list of assistant + * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant) + * Just after user switch, the list of assistant will also reset to empty. + * In both cases,The component's UID of the assistiant role or assistant setting will be + * automitically added to the list by the audio service. + * * @return array of assistants UIDs * * @hide diff --git a/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl index 65633fe6b104..70b4ab676d11 100644 --- a/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl +++ b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl @@ -27,5 +27,7 @@ import android.media.VolumeInfo; oneway interface IAudioDeviceVolumeDispatcher { void dispatchDeviceVolumeChanged(in AudioDeviceAttributes device, in VolumeInfo vol); + void dispatchDeviceVolumeAdjusted(in AudioDeviceAttributes device, in VolumeInfo vol, + int direction, int mode); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index babafaf26036..e28178a8d5d8 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -509,7 +509,8 @@ interface IAudioService { void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register, in IAudioDeviceVolumeDispatcher cb, in String packageName, - in AudioDeviceAttributes device, in List<VolumeInfo> volumes); + in AudioDeviceAttributes device, in List<VolumeInfo> volumes, + boolean handlesvolumeAdjustment); String getHalVersion(); } diff --git a/media/java/android/media/metrics/BundleSession.java b/media/java/android/media/metrics/BundleSession.java index 743d2338d69a..0f0fdfe1ce81 100644 --- a/media/java/android/media/metrics/BundleSession.java +++ b/media/java/android/media/metrics/BundleSession.java @@ -32,6 +32,15 @@ public final class BundleSession implements AutoCloseable { private final @NonNull MediaMetricsManager mManager; private final @NonNull LogSessionId mLogSessionId; + /** + * A key describing the statsd atom into which to place this bundle's other contents. + * The associated value is an integer. + * + * @see #reportBundleMetrics + */ + + public static final String KEY_STATSD_ATOM = "bundlesession-statsd-atom"; + /** @hide */ public BundleSession(@NonNull String id, @NonNull MediaMetricsManager manager) { mId = id; @@ -44,6 +53,10 @@ public final class BundleSession implements AutoCloseable { /** * Reports metrics via bundle. * + * The key {@link #KEY_STATSD_ATOM} references an integer value that + * indicates the statsd atom for the data in this bundle. Other keys + * and their types are defined on a per-atom basis. + * */ public void reportBundleMetrics(@NonNull PersistableBundle metrics) { mManager.reportBundleMetrics(mId, metrics); @@ -68,5 +81,6 @@ public final class BundleSession implements AutoCloseable { @Override public void close() { + mManager.releaseSessionId(mLogSessionId.getStringId()); } } diff --git a/media/java/android/media/metrics/EditingSession.java b/media/java/android/media/metrics/EditingSession.java index 2a48a728a2f0..2ddf623b1ed3 100644 --- a/media/java/android/media/metrics/EditingSession.java +++ b/media/java/android/media/metrics/EditingSession.java @@ -59,5 +59,6 @@ public final class EditingSession implements AutoCloseable { @Override public void close() { + mManager.releaseSessionId(mLogSessionId.getStringId()); } } diff --git a/media/java/android/media/metrics/IMediaMetricsManager.aidl b/media/java/android/media/metrics/IMediaMetricsManager.aidl index a774403b4835..51b1cc27c8a7 100644 --- a/media/java/android/media/metrics/IMediaMetricsManager.aidl +++ b/media/java/android/media/metrics/IMediaMetricsManager.aidl @@ -41,4 +41,6 @@ interface IMediaMetricsManager { String getEditingSessionId(int userId); String getBundleSessionId(int userId); void reportBundleMetrics(in String sessionId, in PersistableBundle metrics, int userId); + + void releaseSessionId(in String sessionId, int userId); } diff --git a/media/java/android/media/metrics/MediaMetricsManager.java b/media/java/android/media/metrics/MediaMetricsManager.java index 7229c471c3b6..0898874c2f65 100644 --- a/media/java/android/media/metrics/MediaMetricsManager.java +++ b/media/java/android/media/metrics/MediaMetricsManager.java @@ -171,6 +171,18 @@ public final class MediaMetricsManager { } /** + * Creates a generic bundle session. + */ + @NonNull + public void releaseSessionId(@NonNull String sessionId) { + try { + mService.releaseSessionId(sessionId, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Reports error event. * @hide */ diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java index aad510e87a7e..f8dd756c5f9c 100644 --- a/media/java/android/media/metrics/PlaybackSession.java +++ b/media/java/android/media/metrics/PlaybackSession.java @@ -100,5 +100,6 @@ public final class PlaybackSession implements AutoCloseable { @Override public void close() { mClosed = true; + mManager.releaseSessionId(mLogSessionId.getStringId()); } } diff --git a/media/java/android/media/metrics/PlaybackStateEvent.java b/media/java/android/media/metrics/PlaybackStateEvent.java index 8e7482534677..cfe0ff81520f 100644 --- a/media/java/android/media/metrics/PlaybackStateEvent.java +++ b/media/java/android/media/metrics/PlaybackStateEvent.java @@ -31,6 +31,11 @@ import java.util.Objects; * Playback state event. */ public final class PlaybackStateEvent extends Event implements Parcelable { + + // RBE -- we should be getting these values from the proto, not doing them + // hand-coded values here. + // frameorks/proto_logging/stats/message/mediametrics_message.pb.h + // package libstatslog? /** Playback has not started (initial state) */ public static final int STATE_NOT_STARTED = 0; /** Playback is buffering in the background for initial playback start */ diff --git a/media/java/android/media/metrics/RecordingSession.java b/media/java/android/media/metrics/RecordingSession.java index d38835149cd8..87cc2501dd70 100644 --- a/media/java/android/media/metrics/RecordingSession.java +++ b/media/java/android/media/metrics/RecordingSession.java @@ -61,5 +61,6 @@ public final class RecordingSession implements AutoCloseable { @Override public void close() { mClosed = true; + mManager.releaseSessionId(mLogSessionId.getStringId()); } } diff --git a/media/java/android/media/metrics/TranscodingSession.java b/media/java/android/media/metrics/TranscodingSession.java index e6d359aec35d..352138e304c1 100644 --- a/media/java/android/media/metrics/TranscodingSession.java +++ b/media/java/android/media/metrics/TranscodingSession.java @@ -59,5 +59,6 @@ public final class TranscodingSession implements AutoCloseable { @Override public void close() { + mManager.releaseSessionId(mLogSessionId.getStringId()); } } diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml index 858f85f78b97..6928b9483078 100644 --- a/media/packages/BluetoothMidiService/AndroidManifest.xml +++ b/media/packages/BluetoothMidiService/AndroidManifest.xml @@ -20,8 +20,6 @@ xmlns:tools="http://schemas.android.com/tools" package="com.android.bluetoothmidiservice" > - <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" /> - <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> <uses-feature android:name="android.software.midi" diff --git a/media/packages/BluetoothMidiService/AndroidManifestBase.xml b/media/packages/BluetoothMidiService/AndroidManifestBase.xml index 99dcaaa5763d..468f6eebff41 100644 --- a/media/packages/BluetoothMidiService/AndroidManifestBase.xml +++ b/media/packages/BluetoothMidiService/AndroidManifestBase.xml @@ -19,7 +19,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.bluetoothmidiservice" > - <uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" /> <application android:label="BluetoothMidi" android:defaultToDeviceProtectedStorage="true" diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java index d541da09f45d..b893b45611fb 100644 --- a/mms/java/android/telephony/MmsManager.java +++ b/mms/java/android/telephony/MmsManager.java @@ -70,7 +70,8 @@ public class MmsManager { } iMms.sendMessage(subId, ActivityThread.currentPackageName(), contentUri, - locationUrl, configOverrides, sentIntent, messageId); + locationUrl, configOverrides, sentIntent, messageId, + mContext.getAttributionTag()); } catch (RemoteException e) { // Ignore it } @@ -102,7 +103,7 @@ public class MmsManager { } iMms.downloadMessage(subId, ActivityThread.currentPackageName(), locationUrl, contentUri, configOverrides, downloadedIntent, - messageId); + messageId, mContext.getAttributionTag()); } catch (RemoteException e) { // Ignore it } diff --git a/mms/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl index e0e0a4a812e4..3cdde10e4fc2 100644 --- a/mms/java/com/android/internal/telephony/IMms.aidl +++ b/mms/java/com/android/internal/telephony/IMms.aidl @@ -26,7 +26,7 @@ import android.os.Bundle; */ interface IMms { /** - * Send an MMS message + * Send an MMS message with attribution tag. * * @param subId the SIM id * @param callingPkg the package name of the calling app @@ -38,10 +38,11 @@ interface IMms { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed * @param messageId An id that uniquely identifies the message requested to be sent. + * @param attributionTag a tag that attributes the call to a client App. */ void sendMessage(int subId, String callingPkg, in Uri contentUri, String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent, - in long messageId); + in long messageId, String attributionTag); /** * Download an MMS message using known location and transaction id @@ -57,10 +58,11 @@ interface IMms { * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed * @param messageId An id that uniquely identifies the message requested to be downloaded. + * @param attributionTag a tag that attributes the call to a client App. */ void downloadMessage(int subId, String callingPkg, String locationUrl, in Uri contentUri, in Bundle configOverrides, - in PendingIntent downloadedIntent, in long messageId); + in PendingIntent downloadedIntent, in long messageId, String attributionTag); /** * Import a text message into system's SMS store diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml index eec09d20eec1..64637c675fd7 100644 --- a/packages/CompanionDeviceManager/res/values-af/strings.xml +++ b/packages/CompanionDeviceManager/res/values-af/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Programme"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Stroom jou foon se programme"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> afstandtoegang tot programme wat op <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> geïnstalleer is wanneer hierdie foon aan die internet gekoppel is."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> afstandtoegang tot programme wat op <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> geïnstalleer is wanneer hierdie tablet aan die internet gekoppel is."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> afstandtoegang tot programme wat op <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> geïnstalleer is wanneer hierdie toestel aan die internet gekoppel is."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Hierdie diens word gebruik om programme tussen jou toestelle te stroom"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Gee <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang tot hierdie inligting op jou foon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Kennisgewings"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kan alle kennisgewings lees, insluitend inligting soos kontakte, boodskappe en foto\'s"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Dienste"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Hierdie diens deel foto\'s, media en kennisgewings van jou foon af na ander dienste"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Hierdie diens deel foto\'s, media en kennisgewings van jou foon af na ander dienste"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Laat toe"</string> <string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dra programtoestemmings na jou horlosie toe oor"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Om dit makliker te maak om jou horlosie op te stel, sal programme wat gedurende opstelling op jou horlosie geïnstalleer word, dieselfde toestemmings as jou foon gebruik.\n\n Hierdie toestemmings kan toegang tot jou horlosie se mikrofoon en ligging insluit."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml index 0411f3aa3f4d..d7baf991b8b9 100644 --- a/packages/CompanionDeviceManager/res/values-am/strings.xml +++ b/packages/CompanionDeviceManager/res/values-am/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"መተግበሪያዎች"</string> <string name="permission_apps_summary" msgid="798718816711515431">"የስልክዎን መተግበሪያዎች በዥረት ይልቀቁ"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ይህን መረጃ ከስልክዎ እንዲደርስበት ይፍቀዱለት"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ሲገናኙ በዚህ ስልክ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ሲገናኙ በዚህ ጡባዊ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ሲገናኙ በዚህ መሳሪያ ላይ የተጫኑ መተግበሪያዎችን እንዲደርስ ለ<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> የርቀት መዳረሻ እንዲያቀርብ ይፍቀዱለት።"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"መሣሪያ ተሻጋሪ አገልግሎቶች"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ይህ አገልግሎት በእርስዎ መሣሪያዎች መካከል መተግበሪያዎችን ለመልቀቅ ስራ ላይ ይውላል"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ይህን መረጃ ከስልክዎ ላይ እንዲደርስ ይፍቀዱለት"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"ማሳወቂያዎች"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"እንደ ውሎች፣ መልዕክቶች እና ፎቶዎች ያሉ መረጃዎችን ጨምሮ ሁሉንም ማሳወቂያዎች ማንበብ ይችላል"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ፎቶዎች እና ሚዲያ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"የGoogle Play አገልግሎቶች"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ይህ አገልግሎት ፎቶዎችን፣ ሚዲያዎችን እና ማሳወቂያዎችን ከስልክዎ ለሌሎች መሣሪያዎች ያጋራል"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ይህ አገልግሎት ፎቶዎችን፣ ሚዲያዎችን እና ማሳወቂያዎችን ከስልክዎ ለሌሎች መሣሪያዎች ያጋራል"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"ፍቀድ"</string> <string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string> - <string name="consent_ok" msgid="3662376764371001106">"እሺ"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"የመተግበሪያ ፈቃዶችን ወደ የእጅ ሰዓትዎ ያስተላልፉ"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"የእጅ ሰዓትዎን ማቀናበርን ለማቅለል በማዋቀር ጊዜ በእጅ ሰዓትዎ ላይ የተጫኑ መተግበሪያዎች እንደ ስልክዎ ተመሳሳይ ፈቃዶችን ይጠቀማሉ።\n\n እነዚህ ፈቃዶች የእጅ ሰዓትዎ ማይክሮፎን እና አካባቢ መዳረሻን ሊያካትቱ ይችላሉ።"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml index 5c00999d6a31..17dde4eb3f23 100644 --- a/packages/CompanionDeviceManager/res/values-ar/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"التطبيقات"</string> <string name="permission_apps_summary" msgid="798718816711515431">"بث تطبيقات هاتفك"</string> <string name="title_app_streaming" msgid="2270331024626446950">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى هذه المعلومات من هاتفك"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بمنح الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الهاتف عندما يكون متصلاً بالإنترنت."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بمنح <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز اللوحي عندما يكون متصلاً بالإنترنت."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بمنح <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> الإذن بالوصول عن بُعد إلى التطبيقات المثبَّتة على هذا الجهاز عندما يكون متصلاً بالإنترنت."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"تُستخدَم هذه الخدمة لبث التطبيقات بين الأجهزة."</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى هذه المعلومات من هاتفك"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"الإشعارات"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"يمكن لهذا الملف الشخصي قراءة جميع الإشعارات، بما في ذلك المعلومات، مثل جهات الاتصال والرسائل والصور."</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"الصور والوسائط"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"خدمات Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"تشارك هذه الخدمة الصور والوسائط والإشعارات من هاتفك إلى أجهزة أخرى."</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"تشارك هذه الخدمة الصور والوسائط والإشعارات من هاتفك إلى أجهزة أخرى."</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"السماح"</string> <string name="consent_no" msgid="2640796915611404382">"عدم السماح"</string> - <string name="consent_ok" msgid="3662376764371001106">"حسنًا"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"نقل أذونات التطبيقات إلى ساعتك"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"لتسهيل إعداد ساعتك، فإن التطبيقات التي يتم تثبيتها على ساعتك أثناء الإعداد ستستخدم الأذونات نفسها التي يستخدمها هاتفك.\n\n قد تشتمل هذه الأذونات على الوصول إلى ميكروفون ساعتك وبيانات موقعها الجغرافي."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml index dbb5c3b000a8..66d187751f21 100644 --- a/packages/CompanionDeviceManager/res/values-as/strings.xml +++ b/packages/CompanionDeviceManager/res/values-as/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"এপ্"</string> <string name="permission_apps_summary" msgid="798718816711515431">"আপোনাৰ ফ’নৰ এপ্ ষ্ট্ৰীম কৰক"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"সংযোগ কৰিলে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক এই ফ’নটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"সংযোগ কৰিলে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক এই টেবলেটটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"সংযোগ কৰিলে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক এই ডিভাইচটোত ইনষ্টল কৰি থোৱা এপ্লিকেশ্বনসমূহ এক্সেছ কৰিবলৈ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ক ৰিম’ট এক্সেছ দিবলৈ দিয়ক।"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"এই সেৱাটো আপোনাৰ ডিভাইচবোৰৰ মাজত এপ্ ষ্ট্ৰীম কৰিবলৈ ব্যৱহাৰ কৰা হয়"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"জাননী"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"চুক্তি, বাৰ্তা আৰু ফট’ৰ দৰে তথ্যকে ধৰি আটাইবোৰ জাননী পঢ়িব পাৰে"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ফট’ আৰু মিডিয়া"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play সেৱা"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"এই সেৱাটোৱে আপোনাৰ ফ\'নৰ পৰা অন্য ডিভাইচলৈ ফট’, মিডিয়া আৰু জাননী শ্বেয়াৰ কৰে"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"এই সেৱাটোৱে আপোনাৰ ফ\'নৰ পৰা অন্য ডিভাইচলৈ ফট’, মিডিয়া আৰু জাননী শ্বেয়াৰ কৰে"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিয়ক"</string> <string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string> - <string name="consent_ok" msgid="3662376764371001106">"ঠিক আছে"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"আপোনাৰ ঘড়ীলৈ এপৰ অনুমতিসমূহ স্থানান্তৰ কৰক"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"আপোনাৰ ঘড়ীটো ছেটআপ কৰাটো অধিক সহজ কৰি তুলিবলৈ, এয়া কৰাৰ সময়ত আপোনাৰ ঘড়ীটোত ইনষ্টল কৰি থোৱা এপ্সমূহে আপোনাৰ ফ’নৰ দৰে একেই অনুমতিসমূহ ব্যৱহাৰ কৰিব।\n\n এই অনুমতিসমূহত আপোনাৰ ঘড়ীৰ মাইক্ৰ’ফ’ন আৰু অৱস্থানৰ এক্সেছ অন্তৰ্ভুক্ত হ’ব পাৰে।"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml index a0b5b8c0c3fd..6a83c2fe3f74 100644 --- a/packages/CompanionDeviceManager/res/values-az/strings.xml +++ b/packages/CompanionDeviceManager/res/values-az/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Tətbiqlər"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun tətbiqlərini yayımlayın"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazının qoşulduqda bu telefonda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazının qoşulduqda bu planşetdə quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> cihazının qoşulduqda bu cihazda quraşdırılmış tətbiqlərə uzaqdan giriş icazəsi verməsinə imkan verin."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Bu xidmət cihazlarınız arasında tətbiqləri yayımlamaq üçün istifadə olunur"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Bildirişlər"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Bütün bildirişləri, o cümlədən müqavilələr, mesajlar və fotolar kimi məlumatları oxuya bilər"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Foto və media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xidmətləri"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Bu xidmət telefonunuzdakı foto, media və bildirişləri digər cihazlarla paylaşır"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Bu xidmət telefonunuzdakı foto, media və bildirişləri digər cihazlarla paylaşır"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"İcazə verin"</string> <string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Tətbiq icazələrini saatınıza köçürün"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Saatınızı ayarlamağı asanlaşdırmaq üçün ayarlama zamanı saatınızda quraşdırılmış tətbiqlər telefonunuzla eyni icazələrdən istifadə edəcək.\n\n Bu icazələrə saatınızın mikrofonuna və məkanına giriş daxil ola bilər."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml index 78cac0a8c092..271597ab4e68 100644 --- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Strimujte aplikacije na telefonu"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da daljinski pristupa aplikacijama instaliranim na telefonu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kada je povezan."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da daljinski pristupa aplikacijama instaliranim na tabletu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kada je povezan."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da daljinski pristupa aplikacijama instaliranim na uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> kada je povezan."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ova usluga se koristi za strimovanje aplikacija između uređaja"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama sa telefona"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Obaveštenja"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Može da čita sva obaveštenja, uključujući informacije poput ugovora, poruka i slika"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Slike i mediji"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ova usluga deli slike, medijski sadržaj i obaveštenja sa telefona na druge uređaje"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ova usluga deli slike, medijski sadržaj i obaveštenja sa telefona na druge uređaje"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string> <string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string> - <string name="consent_ok" msgid="3662376764371001106">"Potvrdi"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenesite dozvole za aplikacije na sat"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Da bismo pojednostavili podešavanje sata, aplikacije instalirane na satu tokom podešavanja će koristiti iste dozvole kao telefon.\n\n Te dozvole mogu da obuhvataju pristup mikrofonu i lokaciji sata."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml index ed521b1bf6fa..11536cb2960d 100644 --- a/packages/CompanionDeviceManager/res/values-be/strings.xml +++ b/packages/CompanionDeviceManager/res/values-be/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Праграмы"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Трансліруйце змесціва праграм з вашага тэлефона"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> мець доступ да гэтай інфармацыі з вашага тэлефона"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> атрымліваць аддалены доступ да праграм, усталяваных на тэлефоне <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> (калі тэлефон падключаны)."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> атрымліваць аддалены доступ да праграм, усталяваных на планшэце <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> (калі планшэт падключаны)."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> атрымліваць аддалены доступ да праграм, усталяваных на прыладзе <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> (калі прылада падключана)."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Гэты сэрвіс выкарыстоўваецца для перадачы праграм плынню паміж прыладамі"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Дазвольце праграме <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> мець доступ да гэтай інфармацыі з вашага тэлефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Апавяшчэнні"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Можа счытваць усе апавяшчэнні, уключаючы паведамленні, фота і інфармацыю пра кантакты"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Фота і медыяфайлы"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Сэрвісы Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Гэты сэрвіс абагульвае з іншымі прыладамі фота, медыяфайлы і апавяшчэнні, якія захоўваюцца на вашым тэлефоне"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Гэты сэрвіс абагульвае з іншымі прыладамі фота, медыяфайлы і апавяшчэнні, якія захоўваюцца на вашым тэлефоне"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Дазволіць"</string> <string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string> - <string name="consent_ok" msgid="3662376764371001106">"ОК"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перанос дазволаў праграм на ваш гадзіннік"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Для праграм, усталяваных на гадзіннік падчас наладжвання, будуць дзейнічаць тыя самыя дазволы, што і на тэлефоне.\n\n Так гадзіннік можа атрымаць доступ да мікрафона і даных пра месцазнаходжанне."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml index fe65bda4b434..0ee73702f4f1 100644 --- a/packages/CompanionDeviceManager/res/values-bg/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Поточно предаване на приложенията на телефона ви"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до тази информация от телефона ви"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предоставя на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> отдалечен достъп до приложенията, инсталирани на този телефон, когато има установена връзка."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предоставя на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> отдалечен достъп до приложенията, инсталирани на този таблет, когато има установена връзка."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да предоставя на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> отдалечен достъп до приложенията, инсталирани на това устройство, когато има установена връзка."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Тази услуга служи за поточно предаване на приложения между устройствата ви"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до тази информация от телефона ви"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Известия"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Може да чете всички известия, включително различна информация, като например договори, съобщения и снимки"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Снимки и мултимедия"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Услуги за Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Тази услуга споделя с други устройства снимки, мултимедия и известия от телефона ви"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Тази услуга споделя с други устройства снимки, мултимедия и известия от телефона ви"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Разрешаване"</string> <string name="consent_no" msgid="2640796915611404382">"Забраняване"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Прехвърляне на разрешенията за приложенията към часовника"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"За по-лесно конфигуриране на часовника ви приложенията, инсталирани на него по време на настройването, ще използват същите разрешения като предоставените на телефона ви.\n\nТе може да включват достъп до микрофона и местоположението на часовника ви."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml index 58c6c265aa96..fb1ede00a257 100644 --- a/packages/CompanionDeviceManager/res/values-bn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"অ্যাপ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"আপনার ফোনের অ্যাপ স্ট্রিমিংয়ের মাধ্যমে কাস্ট করুন"</string> <string name="title_app_streaming" msgid="2270331024626446950">"আপনার ফোন থেকে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> অ্যাপকে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> কে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ফোনে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> কে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ট্যাবলেটে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> কে <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>এ দূরবর্তী অ্যাক্সেস প্রদান করতে দিন যাতে কানেক্ট থাকাকালীন এই ডিভাইসে ইনস্টল করা অ্যাপ্লিকেশনগুলিতে অ্যাক্সেস করা যায়।"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্রস-ডিভাইস পরিষেবা"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"আপনার ডিভাইসের মধ্যে অ্যাপ স্ট্রিম করার জন্য এই পরিষেবা ব্যবহার করা হয়"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"আপনার ফোন থেকে <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-কে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"বিজ্ঞপ্তি"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"চুক্তি, মেসেজ ও ফটোর সহ সব বিজ্ঞপ্তি পড়তে পারে"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"সব বিজ্ঞপ্তি পড়তে পারবে, যার মধ্যে পরিচিতি, মেসেজ ও ফটোর মতো তথ্য অন্তর্ভুক্ত"</string> <string name="permission_storage" msgid="6831099350839392343">"ফটো ও মিডিয়া"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play পরিষেবা"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"এই পরিষেবা আপনার ফোন থেকে অন্যান্য ডিভাইসে ফটো, মিডিয়া ও বিজ্ঞপ্তি শেয়ার করে"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"এই পরিষেবা আপনার ফোন থেকে অন্যান্য ডিভাইসে ফটো, মিডিয়া ও বিজ্ঞপ্তি শেয়ার করে"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"অনুমতি দিন"</string> <string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string> - <string name="consent_ok" msgid="3662376764371001106">"ঠিক আছে"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"অ্যাপকে দেওয়া অনুমতি আপনার ঘড়িতে ট্রান্সফার করুন"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"ঘড়ি আরও সহজে সেট আপ করতে, সেট আপ চলাকালীন আপনার ঘড়িতে ইনস্টল করা অ্যাপ ফোনের মতো একই অনুমতি ব্যবহার করবে।\n\n এইসব অনুমতির মধ্যে আপনার ঘড়ির মাইক্রোফোন ও লোকেশন সম্পর্কে তথ্যের অ্যাক্সেস অন্তর্ভুক্ত থাকতে পারে।"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml index 1ce89443afff..a28cb732879a 100644 --- a/packages/CompanionDeviceManager/res/values-bs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Prenosite aplikacije s telefona"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama s telefona"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> omogući daljinski pristup uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> radi pristupanja aplikacijama instaliranim na ovom telefonu kada je povezan s mrežom."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> omogući daljinski pristup uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> radi pristupanja aplikacijama instaliranim na ovom tabletu kada je povezan s mrežom."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dozvolite da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> omogući daljinski pristup uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> radi pristupanja aplikacijama instaliranim na njemu kada je povezan s mrežom."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ova usluga se koristi za prijenos aplikacija između vaših uređaja"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa ovim informacijama s vašeg telefona"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Obavještenja"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Može čitati sva obavještenja, uključujući informacije kao što su kontakti, poruke i fotografije"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijski sadržaj i obavještenja s vašeg telefona na druge uređaje"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijski sadržaj i obavještenja s vašeg telefona na druge uređaje"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Dozvoli"</string> <string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string> - <string name="consent_ok" msgid="3662376764371001106">"Uredu"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos odobrenja za aplikaciju na sat"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Radi lakšeg postavljanja sata, aplikacije instalirane na satu tokom postavljanja će koristiti ista odobrenja kao i na telefonu.\n\n Ta odobrenja mogu uključivati pristup mikrofonu i lokaciji sata."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml index 0b1847692faf..ad4628753d92 100644 --- a/packages/CompanionDeviceManager/res/values-ca/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplicacions"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Reprodueix en continu aplicacions del telèfon"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcioni accés remot a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedir a les aplicacions instal·lades en aquest telèfon quan estigui connectat."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcioni accés remot a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedir a les aplicacions instal·lades en aquesta tauleta quan estigui connectada."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcioni accés remot a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedir a les aplicacions instal·lades en aquest dispositiu quan estigui connectat."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Aquest servei s\'utilitza per reproduir en continu aplicacions entre dispositius"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permet que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> accedeixi a aquesta informació del telèfon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificacions"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Pot llegir totes les notificacions, inclosa informació com ara els contactes, els missatges i les fotos"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotos i contingut multimèdia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Serveis de Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Aquest servei comparteix fotos, contingut multimèdia i notificacions amb altres dispositius des del teu telèfon"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Aquest servei comparteix fotos, contingut multimèdia i notificacions amb altres dispositius des del teu telèfon"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permet"</string> <string name="consent_no" msgid="2640796915611404382">"No permetis"</string> - <string name="consent_ok" msgid="3662376764371001106">"D\'acord"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfereix els permisos de les aplicacions al teu rellotge"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitar la configuració del rellotge, les aplicacions instal·lades al rellotge durant la configuració utilitzaran els mateixos permisos que al teu telèfon.\n\n Aquests permisos poden incloure l\'accés al micròfon i a la ubicació del rellotge."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml index f89f17ef0c66..15f719a854ff 100644 --- a/packages/CompanionDeviceManager/res/values-cs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikace"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikace v telefonu"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k těmto informacím z vašeho telefonu"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> poskytovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> vzdálený přístup k aplikacím nainstalovaným v tomto telefonu, když je připojen."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> poskytovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> vzdálený přístup k aplikacím nainstalovaným v tomto tabletu, když je připojen."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povolit aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> poskytovat <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> vzdálený přístup k aplikacím nainstalovaným v tomto zařízení, když je připojeno."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Tato služba slouží ke streamování aplikací mezi zařízeními"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k těmto informacím z vašeho telefonu"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Oznámení"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Může číst veškerá oznámení včetně informací, jako jsou kontakty, zprávy a fotky"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotky a média"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Tato služba sdílí fotky, média a oznámení z telefonu do ostatních zařízení"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Tato služba sdílí fotky, média a oznámení z telefonu do ostatních zařízení"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Povolit"</string> <string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Přesunout oprávnění aplikací do hodinek"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Abychom vám usnadnili nastavení hodinek, aplikace nainstalované do hodinek během úvodního nastavení budou používat stejná oprávnění jako váš telefon.\n\n Tato oprávnění mohou zahrnovat přístup k mikrofonu a poloze hodinek."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml index e366bb91d6ac..9868d59ea2bc 100644 --- a/packages/CompanionDeviceManager/res/values-da/strings.xml +++ b/packages/CompanionDeviceManager/res/values-da/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Stream din telefons apps"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Giv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til disse oplysninger fra din telefon"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Giver <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at fjernstyre apps, som er installeret på <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, når telefonen har forbindelse til internettet."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Giver <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at fjernstyre apps, som er installeret på <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, når tabletten har forbindelse til internettet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Giver <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at fjernstyre apps, som er installeret på <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, når enheden har forbindelse til internettet."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Denne tjeneste anvendes til at caste apps mellem dine enheder"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Tillad, at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> får adgang til disse oplysninger fra din telefon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifikationer"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kan læse alle notifikationer, herunder oplysninger som f.eks. kontakter, beskeder og billeder"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Billeder og medier"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Denne tjeneste deler billeder, medier og notifikationer fra din telefon til andre enheder"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Denne tjeneste deler billeder, medier og notifikationer fra din telefon til andre enheder"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Tillad"</string> <string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptilladelser til dit ur"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"For at gøre det nemmere at konfigurere dit ur vil de apps, der installeres under konfigurationen, anvende de samme tilladelser som din telefon.\n\n Disse tilladelser kan omfatte adgang til dit urs mikrofon og lokation."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml index 440e06b54304..d7cb1ef0a030 100644 --- a/packages/CompanionDeviceManager/res/values-de/strings.xml +++ b/packages/CompanionDeviceManager/res/values-de/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Smartphone-Apps streamen"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Besteht eine Verbindung, darf <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> Remotezugriff auf die auf diesem Smartphone installierten Apps geben."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Besteht eine Verbindung, darf <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> Remotezugriff auf die auf diesem Tablet installierten Apps geben."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Besteht eine Verbindung, darf <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> Remotezugriff auf die auf diesem Gerät installierten Apps geben."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Dieser Dienst wird dazu verwendet, Apps zwischen deinen Geräten zu streamen"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Benachrichtigungen"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kann alle Benachrichtigungen lesen, einschließlich Informationen wie Verträgen, Nachrichten und Fotos"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotos und Medien"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Dieser Dienst teilt Fotos, Medien und Benachrichtigungen von deinem Smartphone mit anderen Geräten"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Dieser Dienst teilt Fotos, Medien und Benachrichtigungen von deinem Smartphone mit anderen Geräten"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Zulassen"</string> <string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-Berechtigungen auf Smartwatch übertragen"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Damit sich deine Smartwatch leichter einrichten lässt, erhalten die Apps, die während der Einrichtung auf deiner Smartwatch installiert werden, automatisch die gleichen Berechtigungen wie deine Smartphone-Apps.\n\n Zu diesen Berechtigungen kann der Zugriff auf das Mikrofon und den Standort deiner Smartwatch gehören."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml index 326527c5b0a5..56a9633176a0 100644 --- a/packages/CompanionDeviceManager/res/values-el/strings.xml +++ b/packages/CompanionDeviceManager/res/values-el/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Εφαρμογές"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Μεταδώστε σε ροή τις εφαρμογές του τηλεφώνου σας"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Να επιτρέπεται στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> η πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας."</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να παρέχει απομακρυσμένη πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το τηλέφωνο."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να παρέχει απομακρυσμένη πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτό το tablet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να παρέχει απομακρυσμένη πρόσβαση στη συσκευή <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> κατά τη σύνδεση, προκειμένου να έχει πρόσβαση σε εφαρμογές που έχουν εγκατασταθεί σε αυτήν τη συσκευή."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλών συσκευών"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Αυτή η υπηρεσία χρησιμοποιείται για τη ροή εφαρμογών μεταξύ των συσκευών σας"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Επιτρέψτε στην εφαρμογή <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> να έχει πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Ειδοποιήσεις"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Μπορεί να διαβάσει όλες τις ειδοποιήσεις, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Μπορεί να διαβάσει όλες τις ειδοποιήσεις, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string> <string name="permission_storage" msgid="6831099350839392343">"Φωτογραφίες και μέσα"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Υπηρεσίες Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Αυτή η υπηρεσία κοινοποιεί φωτογραφίες, πολυμέσα και ειδοποιήσεις από το τηλέφωνό σας σε άλλες συσκευές"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Αυτή η υπηρεσία κοινοποιεί φωτογραφίες, πολυμέσα και ειδοποιήσεις από το τηλέφωνό σας σε άλλες συσκευές"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Να επιτρέπεται"</string> <string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Μεταφορά αδειών εφαρμογών στο ρολόι σας"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Για να είναι πιο εύκολη η ρύθμιση του ρολογιού σας, οι εφαρμογές που εγκαθίστανται στο ρολόι σας κατά τη ρύθμιση, θα χρησιμοποιούν τις ίδιες άδειες με το τηλέφωνό σας.\n\n Στις άδειες ενδέχεται να περιλαμβάνεται άδεια πρόσβασης στο μικρόφωνο και την τοποθεσία του ρολογιού σας."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml index 9b8f95942983..cf08be098b63 100644 --- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this phone when connected."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this tablet when connected."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this device when connected."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifications"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string> <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml index 9b8f95942983..cf08be098b63 100644 --- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this phone when connected."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this tablet when connected."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this device when connected."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifications"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string> <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml index 9b8f95942983..cf08be098b63 100644 --- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this phone when connected."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this tablet when connected."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this device when connected."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifications"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string> <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml index 9b8f95942983..cf08be098b63 100644 --- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this phone when connected."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this tablet when connected."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this device when connected."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifications"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information such as contracts, messages and photos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string> <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media and notifications from your phone to other devices"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml index 8bd1c4a76735..03c2991a6411 100644 --- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml +++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this phone when connected."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this tablet when connected."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Let <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to provide <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> remote access to access to applications installed on this device when connected."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"This service is used to stream apps between your devices"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> to access this information from your phone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifications"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Can read all notifications, including information like contracts, messages, and photos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages, and photos"</string> <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"This service shares photos, media, and notifications form your phone to other devices"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"This service shares photos, media, and notifications form your phone to other devices"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Allow"</string> <string name="consent_no" msgid="2640796915611404382">"Don’t allow"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer app permissions to your watch"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"To make it easier to set up your watch, apps installed on your watch during setup will use the same permissions as your phone.\n\n These permissions may include access to your watch’s microphone and location."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml index e5b22a2ed01b..b4dbab302a7b 100644 --- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Transmitir las apps de tu teléfono"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcione a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a las aplicaciones instaladas en este teléfono cuando esté conectado."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcione <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a las aplicaciones instaladas en esta tablet cuando esté conectada."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> proporcione a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a las aplicaciones instaladas en este dispositivo cuando esté conectado."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este servicio se utiliza para transmitir apps entre tus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información de tu teléfono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Puede leer todas las notificaciones, incluso con información como contratos, mensajes y fotos"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este servicio comparte fotos, contenido multimedia y notificaciones de tu teléfono a otros dispositivos"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este servicio comparte fotos, contenido multimedia y notificaciones de tu teléfono a otros dispositivos"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"No permitir"</string> - <string name="consent_ok" msgid="3662376764371001106">"Aceptar"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfiere los permisos de la app a tu reloj"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Para que sea más fácil configurar tu reloj, las apps que se instalen en este durante la configuración usarán los mismos permisos que tu teléfono.\n\n Es posible que estos permisos incluyan el acceso al micrófono y a la ubicación del reloj."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml index 1a988e96aaef..79e554cae429 100644 --- a/packages/CompanionDeviceManager/res/values-es/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplicaciones"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Emite las aplicaciones de tu teléfono"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde tu teléfono"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda de forma remota a las aplicaciones instaladas en este teléfono cuando <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> esté conectado a Internet."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda de forma remota a las aplicaciones instaladas en este tablet cuando <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> esté conectado a Internet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda de forma remota a las aplicaciones instaladas en este dispositivo cuando <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> esté conectado a Internet."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este servicio se usa para emitir aplicaciones en otros dispositivos tuyos"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde tu teléfono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Puede leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos y elementos multimedia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este servicio comparte fotos, archivos multimedia y notificaciones de tu teléfono con otros dispositivos"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este servicio comparte fotos, archivos multimedia y notificaciones de tu teléfono con otros dispositivos"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"No permitir"</string> - <string name="consent_ok" msgid="3662376764371001106">"Aceptar"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir permisos de aplicaciones a tu reloj"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Para configurar fácilmente tu reloj, las aplicaciones que instales en él durante la configuración usarán los mismos permisos que tengan en tu teléfono.\n\n Estos permisos pueden incluir acceso al micrófono y a la ubicación del reloj."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml index f3b8ea92817c..f3e55c2b1616 100644 --- a/packages/CompanionDeviceManager/res/values-et/strings.xml +++ b/packages/CompanionDeviceManager/res/values-et/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Rakendused"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Telefoni rakenduste voogesitamine"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lubatakse seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse telefoni installitud rakendustele."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lubatakse seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse tahvelarvutisse installitud rakendustele."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lubatakse seadmele <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> pakkuda kaugjuurdepääsu, et ühendatuna pääseda juurde sellesse seadmesse installitud rakendustele."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Seda teenust kasutatakse rakenduste voogesitamiseks teie seadmete vahel"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Märguanded"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kõikide märguannete, sealhulgas teabe, nagu kontaktid, sõnumid ja fotod, lugemine"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"See teenus jagab muude seadmetega teie telefonist pärit fotosid, meediat ja märguandeid"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"See teenus jagab muude seadmetega teie telefonist pärit fotosid, meediat ja märguandeid"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Luba"</string> <string name="consent_no" msgid="2640796915611404382">"Ära luba"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Rakenduste lubade kellale ülekandmine"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Selleks et muuta kella seadistamine lihtsamaks, kasutavad teie kellas seadistamise ajal installitud rakendused samasid lubasid, mis neile telefonis antud on.\n\n Need load võivad hõlmata juurdepääsuluba kella mikrofonile ja asukohale."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index 0d4f073be50b..2d9a4c70ba3c 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikazioak"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Igorri zuzenean telefonoko aplikazioak"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Utzi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> urrunetik atzitzen, telefonoa konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Utzi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> urrunetik atzitzen, tableta konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Utzi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> urrunetik atzitzen, gailua konektatuta dagoenean bertan instalatuta dauden aplikazioetarako sarbidea izateko."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu bat baino gehiagotarako zerbitzuak"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Gailuen artean aplikazioak igortzeko erabiltzen da zerbitzua"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Eman informazio hori telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Jakinarazpenak"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Jakinarazpen guztiak irakur ditzake; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Zerbitzuak telefonoko argazkiak, multimedia-edukia eta jakinarazpenak partekatzen ditu beste gailuekin"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Zerbitzuak telefonoko argazkiak, multimedia-edukia eta jakinarazpenak partekatzen ditu beste gailuekin"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Eman baimena"</string> <string name="consent_no" msgid="2640796915611404382">"Ez eman baimenik"</string> - <string name="consent_ok" msgid="3662376764371001106">"Ados"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferitu aplikazio-baimenak erlojura"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Erlojua errazago konfiguratzeko, konfigurazio-prozesua abian zen bitartean erlojuan instalatutako aplikazioek telefonoak darabiltzan baimen berak erabiliko dituzte.\n\n Baliteke baimen horien artean erlojuaren mikrofonoa eta kokapena atzitzeko baimenak egotea."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml index cb14c27c333e..b212b5fdb9c4 100644 --- a/packages/CompanionDeviceManager/res/values-fa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"برنامهها"</string> <string name="permission_apps_summary" msgid="798718816711515431">"جاریسازی برنامههای تلفن"</string> <string name="title_app_streaming" msgid="2270331024626446950">"اجازه دادن به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> برای دسترسی به اطلاعات تلفن"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهد برای <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی ازراهدور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامههای نصبشده در این تلفن دسترسی داشته باشد."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهد برای <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی ازراهدور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامههای نصبشده در این رایانه لوحی دسترسی داشته باشد."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"به <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اجازه میدهد برای <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> دسترسی ازراهدور ارائه دهد تا دستگاه موردنظر بتواند هنگام اتصال، به برنامههای نصبشده در این دستگاه دسترسی داشته باشد."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"سرویسهای بیندستگاهی"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"از این سرویس برای جاریسازی برنامهها میان دستگاههایتان استفاده میشود"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> مجاز میشود به این اطلاعات در دستگاهتان دسترسی پیدا کند"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"اعلانها"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"میتواند همه اعلانها، ازجمله اطلاعاتی مثل قراردادها، پیامها، و عکسها را بخواند"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"میتواند همه اعلانها، ازجمله اطلاعاتی مثل مخاطبین، پیامها، و عکسها را بخواند"</string> <string name="permission_storage" msgid="6831099350839392343">"عکسها و رسانهها"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"خدمات Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"این سرویس عکسها، رسانه، و اعلانهای تلفن را با دستگاههای دیگر همرسانی میکند"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"این سرویس عکسها، رسانه، و اعلانهای تلفن را با دستگاههای دیگر همرسانی میکند"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"مجاز است"</string> <string name="consent_no" msgid="2640796915611404382">"مجاز نبودن"</string> - <string name="consent_ok" msgid="3662376764371001106">"تأیید"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"انتقال اجازههای برنامه به ساعت"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"برای آسانتر کردن راهاندازی ساعت، برنامههای نصبشده در ساعت درحین راهاندازی از همان اجازههای تلفن استفاده خواهند کرد.\n\n ممکن است این اجازهها شامل دسترسی به میکروفون و مکان ساعت باشد."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml index a1c15f131892..194bd86ae983 100644 --- a/packages/CompanionDeviceManager/res/values-fi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Sovellukset"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Striimaa puhelimen sovelluksia"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Salli, että <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> saa pääsyn näihin puhelimesi tietoihin"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Salli, että <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> voi saada sovellukselta (<strong><xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle puhelimelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Salli, että <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> voi saada sovellukselta (<strong><xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle tabletille asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Salli, että <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> voi saada sovellukselta (<strong><xliff:g id="APP_NAME">%1$s</xliff:g>) etäpääsyoikeuden tälle laitteelle asennettuihin sovelluksiin, kun laitteet on yhdistetty."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Palvelua käytetään sovellusten striimaukseen laitteiden välillä"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Salli pääsy tähän tietoon puhelimellasi: <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Ilmoitukset"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Voi lukea kaikkia ilmoituksia, kuten sopimuksiin, viesteihin ja kuviin liittyviä tietoja"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Kuvat ja media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Palvelut"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Palvelu jakaa kuvia, mediaa ja ilmoituksia puhelimelta muille laitteille"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Palvelu jakaa kuvia, mediaa ja ilmoituksia puhelimelta muille laitteille"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Salli"</string> <string name="consent_no" msgid="2640796915611404382">"Älä salli"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Siirrä sovellusluvat kelloon"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Sovellukset, jotka on asennettu kelloon käyttöönoton aikana, käyttävät samoja lupia kuin puhelin. Näin kello on helpompi ottaa käyttöön.\n\n Näihin lupiin saattaa kuulua pääsy kellon mikrofoniin ja sijaintiin."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml index 5bc04397f5fa..066c88c8a79b 100644 --- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Applications"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Diffusez les applications de votre téléphone"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permettez à l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> de donner à l\'appareil <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> un accès à distance aux applications installées sur ce téléphone lorsqu\'il est connecté."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permettez à l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> de donner à l\'appareil <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> un accès à distance aux applications installées sur cette tablette lorsqu\'elle est connectée."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permettez à l\'application <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> de donner à l\'appareil <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> un accès à distance aux applications installées sur cet appareil lorsqu\'il est connecté."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ce service est utilisé pour diffuser des applications entre vos appareils"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autorisez <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations à partir de votre téléphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifications"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Peut lire toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ce service partage des photos, du contenu multimédia et des notifications à partir de votre téléphone vers d\'autres appareils"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ce service partage des photos, du contenu multimédia et des notifications à partir de votre téléphone vers d\'autres appareils"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string> <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'application à votre montre"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Pour faciliter la configuration de votre montre, les applications installées sur celle-ci reprennent les mêmes autorisations que celles installées sur votre téléphone.\n\n Ces autorisations peuvent comprendre l\'accès au microphone et à la position de votre montre."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml index acf4cd6d2ef2..1ffac0934ab9 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Applis"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Caster les applis de votre téléphone"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à distance aux applis installées sur <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> quand ce téléphone est connecté à Internet."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à distance aux applis installées sur <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> quand cette tablette est connectée à Internet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à distance aux applis installées sur <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> quand cet appareil est connecté à Internet."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ce service est utilisé pour caster des applis d\'un appareil à l\'autre"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autoriser <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> à accéder à ces informations depuis votre téléphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifications"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Peut lire toutes les notifications, y compris des informations, comme les contacts, messages et photos"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Photos et contenus multimédias"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ce service partage les photos, les contenus multimédias et les notifications de votre téléphone vers d\'autres appareils"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ce service partage les photos, les contenus multimédias et les notifications de votre téléphone vers d\'autres appareils"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Autoriser"</string> <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transférer les autorisations de l\'appli vers la montre"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Pour que votre montre soit plus facile à configurer, les applis qui y sont installées pendant la configuration utiliseront les mêmes autorisations que votre téléphone.\n\n Il peut s\'agir, par exemple, de l\'accès au micro et à la position de votre montre."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml index d5f851580839..4784ad077267 100644 --- a/packages/CompanionDeviceManager/res/values-gl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplicacións"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Emite as aplicacións do teu teléfono"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde o teu teléfono"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lle outorgue a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a aplicacións instaladas neste teléfono cando teña conexión a Internet."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lle outorgue a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a aplicacións instaladas nesta tableta cando teña conexión a Internet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permite que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> lle outorgue a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acceso remoto a aplicacións instaladas neste dispositivo cando teña conexión a Internet."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este servizo utilízase para reproducir aplicacións en tempo real entre os teus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permitir que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acceda a esta información desde o teu teléfono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificacións"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotos e contido multimedia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servizos de Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este servizo comparte con outros dispositivos as fotos, o contido multimedia e as notificacións do teu teléfono"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este servizo comparte con outros dispositivos as fotos, o contido multimedia e as notificacións do teu teléfono"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"Non permitir"</string> - <string name="consent_ok" msgid="3662376764371001106">"Aceptar"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir os permisos de aplicacións ao reloxo"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Para que che resulte máis doado configurar o reloxo, as aplicacións que instales nel durante a configuración usarán os mesmos permisos que o teléfono.\n\n Entre estes permisos poden estar incluídos os de acceso ao micrófono e á localización do teléfono."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml index adfc6a0cc938..8debe29a486d 100644 --- a/packages/CompanionDeviceManager/res/values-gu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"ઍપ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"તમારા ફોનની ઍપ સ્ટ્રીમ કરો"</string> <string name="title_app_streaming" msgid="2270331024626446950">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને મંજૂરી આપો"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ફોન પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને પ્રદાન કરવા દો."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ટૅબ્લેટ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને પ્રદાન કરવા દો."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"જ્યારે કનેક્ટ કરવામાં આવે, ત્યારે આ ડિવાઇસ પર ઇન્સ્ટૉલ કરવામાં આવેલી ઍપ્લિકેશનોનો રિમોટ ઍક્સેસ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>ને પ્રદાન કરવા દો."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"આ સેવાનો ઉપયોગ તમારા ડિવાઇસ વચ્ચે ઍપ સ્ટ્રીમ કરવા માટે કરવામાં આવે છે"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ને મંજૂરી આપો"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"નોટિફિકેશન"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"સંપર્કો, મેસેજ અને ફોટા જેવી માહિતી સહિતના બધા નોટિફિકેશન વાંચી શકે છે"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ફોટા અને મીડિયા"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play સેવાઓ"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"આ સેવા ફોટા, મીડિયા અને નોટિફિકેશનને તમારા ફોન પરથી અન્ય ડિવાઇસ પર શેર કરે છે"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"આ સેવા ફોટા, મીડિયા અને નોટિફિકેશનને તમારા ફોન પરથી અન્ય ડિવાઇસ પર શેર કરે છે"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"મંજૂરી આપો"</string> <string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string> - <string name="consent_ok" msgid="3662376764371001106">"ઓકે"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"તમારી ઘડિયાળમાં ઍપ પરવાનગીઓ ટ્રાન્સફર કરો"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"તમારી ઘડિયાળનું સેટઅપ કરવાનું સરળ બનાવવા માટે, સેટઅપ દરમિયાન તમારી ઘડિયાળ પર ઇન્સ્ટૉલ કરેલી ઍપ દ્વારા તમારા ફોન પર મળેલી પરવાનગીઓનો ઉપયોગ કરવામાં આવશે.\n\n આ પરવાનગીઓમાં તમારી ઘડિયાળના માઇક્રોફોન અને સ્થાન સંબંધિત માહિતીનો ઍક્સેસ શામેલ હોઈ શકે છે."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml index 71c5f12d4ac2..f48c8e27ed9f 100644 --- a/packages/CompanionDeviceManager/res/values-hi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"ऐप्लिकेशन"</string> <string name="permission_apps_summary" msgid="798718816711515431">"अपने फ़ोन के ऐप्लिकेशन को स्ट्रीम करें"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट होने पर, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> के रिमोट ऐक्सेस की अनुमति दें, ताकि इस फ़ोन पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट होने पर, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> के रिमोट ऐक्सेस की अनुमति दें, ताकि इस टैबलेट पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट होने पर, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> के रिमोट ऐक्सेस की अनुमति दें, ताकि इस डिवाइस पर इंस्टॉल किए गए ऐप्लिकेशन ऐक्सेस किए जा सकें."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"इस सेवा का इस्तेमाल, आपके डिवाइसों के बीच ऐप्लिकेशन कास्ट करने के लिए किया जाता है"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"सूचनाएं"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"इससे सभी सूचनाएं देखी जा सकती हैं. इसमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल है"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवाएं"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"इस सेवा की मदद से, आपके फ़ोन से फ़ोटो, मीडिया, और सूचनाओं को दूसरे डिवाइसों के साथ शेयर किया जाता है"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"इस सेवा की मदद से, आपके फ़ोन से फ़ोटो, मीडिया, और सूचनाओं को दूसरे डिवाइसों के साथ शेयर किया जाता है"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"अनुमति दें"</string> <string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string> - <string name="consent_ok" msgid="3662376764371001106">"ठीक है"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ऐप्लिकेशन से जुड़ी अनुमतियों को अपनी वॉच में ट्रांसफ़र करें"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"वॉच को सेट अप करने की प्रोसेस को आसान बनाने के लिए, उस पर इंस्टॉल किए गए ऐप्लिकेशन को भी वही अनुमतियां मिलेंगी जो आपने उन ऐप्लिकेशन को फ़ोन पर दी होंगी.\n\n इन अनुमतियों में, आपकी वॉच के माइक्रोफ़ोन और जगह की जानकारी का ऐक्सेस शामिल हो सकता है."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml index fd7e30275ddf..ae9421a27d7e 100644 --- a/packages/CompanionDeviceManager/res/values-hr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikacija vašeg telefona"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da telefonu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> omogući udaljeni pristup aplikacijama koje su instalirane na tom telefonu kada su povezani."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da tabletu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> omogući udaljeni pristup aplikacijama koje su instalirane na tom tabletu kada su povezani."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Dopustite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da uređaju <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> omogući udaljeni pristup aplikacijama koje su instalirane na tom uređaju kada su povezani."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ova se usluga koristi za streaming aplikacija između vaših uređaja"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Omogućite aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da pristupa informacijama s vašeg telefona"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Obavijesti"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Može čitati sve obavijesti, uključujući informacije kao što su kontakti, poruke i fotografije"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Usluge za Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijske sadržaje i obavijesti s vašeg telefona na druge uređaje"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ova usluga dijeli fotografije, medijske sadržaje i obavijesti s vašeg telefona na druge uređaje"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Dopusti"</string> <string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string> - <string name="consent_ok" msgid="3662376764371001106">"U redu"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prijenos dopuštenja aplikacije na sat"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Kako bi postavljanje sata bilo jednostavnije, aplikacije instalirane na satu će tijekom postavljanja upotrebljavati ista dopuštenja kao telefon.\n\n Ta dopuštenja mogu uključivati pristup mikrofonu i lokaciji sata."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index c9ef48ad83f7..6428a18eae19 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Alkalmazások"</string> <string name="permission_apps_summary" msgid="798718816711515431">"A telefon alkalmazásainak streamelése"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Engedélyezheti a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazásnak, hogy a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> eszköz számára távoli hozzáférést biztosítson a telefonra telepített alkalmazásokhoz, amikor a telefon csatlakoztatva van."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Engedélyezheti a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazásnak, hogy a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> eszköz számára távoli hozzáférést biztosítson a táblagépre telepített alkalmazásokhoz, amikor a táblagép csatlakoztatva van."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Engedélyezheti a(z) <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> alkalmazásnak, hogy a(z) <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> eszköz számára távoli hozzáférést biztosítson az eszközre telepített alkalmazásokhoz, amikor az eszköz csatlakoztatva van."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ez a szolgáltatás az eszközök közötti alkalmazásstreamelésre szolgál"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Értesítések"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Elolvashat minden értesítést, ideértve az olyan információkat, mint a névjegyek, az üzenetek és a fotók"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-szolgáltatások"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ezzel a szolgáltatással fényképeket, médiatartalmakat és értesítéseket küldhet át a telefonjáról más eszközökre"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ezzel a szolgáltatással fényképeket, médiatartalmakat és értesítéseket küldhet át a telefonjáról más eszközökre"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Engedélyezés"</string> <string name="consent_no" msgid="2640796915611404382">"Tiltás"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Alkalmazásengedélyek átvitele az órára"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Az óra beállításának megkönnyítése érdekében a beállítás során az órára telepített alkalmazások ugyanazokat az engedélyeket használják majd, mint a telefonja.\n\n Ezek az engedélyek magukban foglalhatják az óra mikrofonjához és helyadataihoz való hozzáférést."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml index 77c8befc6e24..8a6ae3f46ae6 100644 --- a/packages/CompanionDeviceManager/res/values-hy/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Հավելվածներ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Հեռարձակել հեռախոսի հավելվածները"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Թույլ տվեք, որ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը կապի հաստատման դեպքում <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ին տրամադրի այս հեռախոսում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Թույլ տվեք, որ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը կապի հաստատման դեպքում <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ին տրամադրի այս պլանշետում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Թույլ տվեք, որ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածը ինտերնետ կապի հաստատման դեպքում <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ին տրամադրի այս սարքում տեղադրված հավելվածներ հեռակա մուտք գործելու թույլտվություն։"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Այս ծառայությունն օգտագործվում է ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Ծանուցումներ"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Կարող է կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Կարող է կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string> <string name="permission_storage" msgid="6831099350839392343">"Լուսանկարներ և մուլտիմեդիա"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ծառայություններ"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Այս ծառայությունը ձեր հեռախոսից լուսանկարներ, մեդիա ֆայլեր և ծանուցումներ է ուղարկում այլ սարքերի"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Այս ծառայությունը ձեր հեռախոսից լուսանկարներ, մեդիա ֆայլեր և ծանուցումներ է ուղարկում այլ սարքերի"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Թույլատրել"</string> <string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string> - <string name="consent_ok" msgid="3662376764371001106">"Եղավ"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Հավելվածների թույլտվությունների տեղափոխում ժամացույց"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Կարգավորման ժամանակ ժամացույցում տեղադրված հավելվածների համար կօգտագործվեն նույն թույլտվությունները, ինչ հեռախոսում։\n\n Այդ թույլտվությունները կարող են ներառել ժամացույցի խոսափողի կամ տեղադրության տվյալների օգտագործումը։"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml index ff4363cc7c59..1bec1da1d32a 100644 --- a/packages/CompanionDeviceManager/res/values-in/strings.xml +++ b/packages/CompanionDeviceManager/res/values-in/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikasi"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Melakukan streaming aplikasi ponsel Anda"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses informasi ini dari ponsel Anda"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberikan akses jarak jauh ke <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> guna mengakses aplikasi yang diinstal di ponsel ini saat terhubung."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberikan akses jarak jauh ke <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> guna mengakses aplikasi yang diinstal di tablet ini saat terhubung."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberikan akses jarak jauh ke <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> guna mengakses aplikasi yang diinstal di perangkat ini saat terhubung."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Layanan ini digunakan untuk menstreaming aplikasi antar-perangkat"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses informasi ini dari ponsel Anda"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifikasi"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Dapat membaca semua notifikasi, termasuk informasi seperti kontak, pesan, dan foto"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Layanan Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Layanan ini membagikan foto, media, dan notifikasi dari ponsel Anda ke perangkat lain"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Layanan ini membagikan foto, media, dan notifikasi dari ponsel Anda ke perangkat lain"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Izinkan"</string> <string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string> - <string name="consent_ok" msgid="3662376764371001106">"Oke"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfer izin aplikasi ke smartwatch"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Untuk mempermudah penyiapan smartwatch, aplikasi yang diinstal di smartwatch selama penyiapan akan menggunakan izin yang sama dengan ponsel.\n\n Izin ini dapat meliputi akses ke mikrofon dan lokasi smartwatch."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml index b8646c7ae976..2857f0b63cb8 100644 --- a/packages/CompanionDeviceManager/res/values-is/strings.xml +++ b/packages/CompanionDeviceManager/res/values-is/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Forrit"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Streymdu forritum símans"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að veita <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjaraðgang að forritum sem eru sett upp í þessum síma þegar tenging er á."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að veita <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjaraðgang að forritum sem eru sett upp í þessari spjaldtölvu þegar tenging er á."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leyfa <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> að veita <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjaraðgang að forritum sem eru sett upp í þessu tæki þegar tenging er á."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Þessi þjónusta er notuð til að streyma forritum á milli tækjanna þinna"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Veita <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aðgang að þessum upplýsingum úr símanum þínum"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Tilkynningar"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Getur lesið allar tilkynningar, þar á meðal upplýsingar á borð við samninga, skilaboð og myndir"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Myndir og efni"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Þjónusta Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Þessi þjónusta deilir myndum, margmiðlunarefni og tilkynningum úr símanum yfir í önnur tæki"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Þessi þjónusta deilir myndum, margmiðlunarefni og tilkynningum úr símanum yfir í önnur tæki"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Leyfa"</string> <string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string> - <string name="consent_ok" msgid="3662376764371001106">"Í lagi"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Flytja heimildir forrita yfir í úrið"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Til að auðvelda uppsetningu úrsins munu forrit sem eru sett upp í úrinu við uppsetningu nota sömu heimildir og stilltar eru í símanum.\n\n Þessar heimildir kunna að fela í sér aðgang að hljóðnema og staðsetningu úrsins."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml index 4dfb69bbc7d1..d165d97ed35d 100644 --- a/packages/CompanionDeviceManager/res/values-it/strings.xml +++ b/packages/CompanionDeviceManager/res/values-it/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"App"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Trasmetti in streaming le app del tuo telefono"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a queste informazioni dal tuo telefono"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di fornire l\'accesso remoto a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedere alle applicazioni installate su questo telefono quando è connesso."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di fornire l\'accesso remoto a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedere alle applicazioni installate su questo tablet quando è connesso."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Consenti all\'app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di fornire l\'accesso remoto a <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> per accedere alle applicazioni installate su questo dispositivo quando è connesso."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Questo servizio viene utilizzato per trasmettere in streaming le app tra i dispositivi"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Consenti a <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> di accedere a questa informazione dal tuo telefono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notifiche"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Puoi leggere tutte le notifiche, incluse le informazioni come contatti, messaggi e foto"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Questo servizio condivide foto, contenuti multimediali e notifiche del telefono con altri dispositivi"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Questo servizio condivide foto, contenuti multimediali e notifiche del telefono con altri dispositivi"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Consenti"</string> <string name="consent_no" msgid="2640796915611404382">"Non consentire"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Trasferisci le autorizzazioni app all\'orologio"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Per facilitare la configurazione dell\'orologio, le app installate su quest\'ultimo durante la configurazione useranno le stesse autorizzazioni delle app sul telefono.\n\n Queste autorizzazioni potrebbero includere l\'accesso al microfono e alla posizione dell\'orologio."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml index a6373c108b55..08445e6ff8ac 100644 --- a/packages/CompanionDeviceManager/res/values-iw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"אפליקציות"</string> <string name="permission_apps_summary" msgid="798718816711515431">"שידור אפליקציות מהטלפון"</string> <string name="title_app_streaming" msgid="2270331024626446950">"מתן אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לגשת למידע הזה מהטלפון שלך"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"האפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> יכולה לספק ל-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטלפון הזה כשיש חיבור."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"האפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> יכולה לספק ל-<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> גישה מרחוק כדי לגשת לאפליקציות שמותקנות בטאבלט הזה כשיש חיבור."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"האפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> יכולה לספק למכשיר <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> גישה מרחוק כדי לגשת לאפליקציות שמותקנות במכשיר הזה כשיש חיבור."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"השירות הזה משמש לשידור אפליקציות בין המכשירים שברשותך"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"מתן אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לגשת למידע הזה מהטלפון שלך"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"התראות"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"גישה לכל ההתראות, כולל מידע כמו אנשי קשר, הודעות ותמונות"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"תמונות ומדיה"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"השירות הזה משמש לשיתוף של תמונות, מדיה והתראות מהטלפון שלך עם מכשירים אחרים"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"השירות הזה משמש לשיתוף של תמונות, מדיה והתראות מהטלפון שלך עם מכשירים אחרים"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"יש אישור"</string> <string name="consent_no" msgid="2640796915611404382">"אין אישור"</string> - <string name="consent_ok" msgid="3662376764371001106">"אישור"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"העברת ההרשאות הניתנות לאפליקציות אל השעון שלך"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"כדי לפשט את הגדרת השעון, אפליקציות שמותקנות במהלך ההגדרה יקבלו את אותן הרשאות שניתנו בטלפון.\n\n ההרשאות האלה עשויות לכלול גישה למיקרופון ולמיקום של השעון."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml index 392ca0aa74d4..14566c746cc6 100644 --- a/packages/CompanionDeviceManager/res/values-ja/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"アプリ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"スマートフォンのアプリのストリーミング"</string> <string name="title_app_streaming" msgid="2270331024626446950">"スマートフォンのこの情報へのアクセスを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"インターネット接続時に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> がスマートフォン内にインストールされているアプリにリモートでアクセスすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可します。"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"インターネット接続時に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> がタブレット内にインストールされているアプリにリモートでアクセスすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可します。"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"インターネット接続時に <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> がデバイス内にインストールされているアプリにリモートでアクセスすることを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可します。"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"クロスデバイス サービス"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"本サービスは、デバイス間でのアプリのストリーミングに使用されます"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"このスマートフォンからの情報へのアクセスを <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> に許可"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"通知"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"連絡先、メッセージ、写真に関する情報を含め、すべての通知を読み取ることができます"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"写真とメディア"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 開発者サービス"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"本サービスは、スマートフォンから他のデバイスに写真、メディア、通知を共有します"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"本サービスは、スマートフォンから他のデバイスに写真、メディア、通知を共有します"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"許可"</string> <string name="consent_no" msgid="2640796915611404382">"許可しない"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"スマートウォッチへのアプリの権限の移行"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"スマートウォッチのセットアップを簡単にするため、セットアップ時にスマートウォッチにインストールされたアプリに、スマートフォンと同じ権限が適用されます。\n\n これらの権限には、スマートウォッチのマイクや位置情報へのアクセス権も含まれることがあります。"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml index f057b8bcc448..f0c3dc98f380 100644 --- a/packages/CompanionDeviceManager/res/values-ka/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"აპები"</string> <string name="permission_apps_summary" msgid="798718816711515431">"თქვენი ტელეფონის აპების სტრიმინგი"</string> <string name="title_app_streaming" msgid="2270331024626446950">"ნება დართეთ, რომ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"მიეცით <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს საშუალება, <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ისთვის დაუშვას დისტანციური წვდომა ამ ტელეფონზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"მიეცით <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს საშუალება, <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ისთვის დაუშვას დისტანციური წვდომა ამ ტაბლეტზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"მიეცით <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ს საშუალება, <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-ისთვის დაუშვას დისტანციური წვდომა ამ მოწყობილობაზე დაინსტალირებულ აპებზე მასთან დაკავშირებისას."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"მოწყობილობათშორისი სერვისები"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ეს სერვისი გამოიყენება აპების მოწყობილობებს შორის სტრიმინგისთვის"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ნება დართეთ, რომ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"შეტყობინებები"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"შეუძლია წაიკითხოს ყველა შეტყობინება, მათ შორის ისეთი ინფორმაცია, როგორიცაა კონტრაქტები, ტექსტური გზავნილები და ფოტოები"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"შეუძლია წაიკითხოს ყველა შეტყობინება, მათ შორის ისეთი ინფორმაცია, როგორიცაა კონტაქტები, ტექსტური შეტყობინებები და ფოტოები"</string> <string name="permission_storage" msgid="6831099350839392343">"ფოტოები და მედია"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ეს სერვისი ფოტოებს, მედიას და შეტყობინებებს აზიარებს თქვენი ტელეფონიდან სხვა მოწყობილობებზე"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ეს სერვისი ფოტოებს, მედიას და შეტყობინებებს აზიარებს თქვენი ტელეფონიდან სხვა მოწყობილობებზე"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"დაშვება"</string> <string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string> - <string name="consent_ok" msgid="3662376764371001106">"კარგი"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"აპის ნებართვების საათისთვის გადაცემა"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"საათის დაყენების გასამარტივებლად თქვენს საათში დაინსტალირებული აპები იმავე ნებართვებს გამოიყენებს, რასაც ტელეფონზე იყენებს.\n\n ეს ნებართვები, შესაძლოა, მოიცავდეს თქვენი საათის მიკროფონსა და მდებარეობაზე წვდომას."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml index 365020c58853..607930da4d5e 100644 --- a/packages/CompanionDeviceManager/res/values-kk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Қолданбалар"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Телефон қолданбаларын трансляциялайды."</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> желіге қосылған кезде, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына осы телефонға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> желіге қосылған кезде, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына осы планшетке орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> желіге қосылған кезде, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына осы құрылғыға орнатылған қолданбаларды қашықтан пайдалануына рұқсат етіңіз."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Аралық құрылғы қызметтері"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Бұл қызмет құрылғылар арасында қолданбаларды трансляциялау үшін пайдаланылады."</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Хабарландырулар"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Барлық хабарландыруды, соның ішінде контактілер, хабарлар және фотосуреттер сияқты ақпаратты оқи алады."</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Фотосуреттер мен медиафайлдар"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play қызметтері"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Бұл қызмет телефоныңыздағы фотосуреттерді, мультимедианы және хабарландыруларды басқа құрылғылармен бөліседі."</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Бұл қызмет телефоныңыздағы фотосуреттерді, мультимедианы және хабарландыруларды басқа құрылғылармен бөліседі."</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Рұқсат беру"</string> <string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string> - <string name="consent_ok" msgid="3662376764371001106">"Жарайды"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Қолданба рұқсаттарын сағатқа ауыстыру"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Реттеу кезінде сағатқа орнатылған қолданбалар телефондағыдай рұқсаттарды пайдаланады. Осылайша сағат оңай реттеледі.\n\n Бұл рұқсаттар сағаттың микрофоны мен геодерегін пайдалануды қамтиды."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml index e1dbaf5fbc5b..814b327cc4f9 100644 --- a/packages/CompanionDeviceManager/res/values-km/strings.xml +++ b/packages/CompanionDeviceManager/res/values-km/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"កម្មវិធី"</string> <string name="permission_apps_summary" msgid="798718816711515431">"បញ្ចាំងកម្មវិធីរបស់ទូរសព្ទអ្នក"</string> <string name="title_app_streaming" msgid="2270331024626446950">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើទូរសព្ទនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើថេប្លេតនេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ផ្ដល់ការចូលប្រើពីចម្ងាយដល់ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ដើម្បីចូលប្រើកម្មវិធី ដែលបានដំឡើងនៅលើឧបករណ៍នេះ នៅពេលភ្ជាប់អ៊ីនធឺណិត។"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"សេវាកម្មនេះត្រូវបានប្រើដើម្បីភ្ជាប់កម្មវិធីរវាងឧបករណ៍របស់អ្នក"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"អនុញ្ញាតឱ្យ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលមើលព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"ការជូនដំណឹង"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"អាចអានការជូនដំណឹងទាំងអស់ រួមទាំងព័ត៌មានដូចជាទំនាក់ទំនង សារ និងរូបថត"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"អាចអានការជូនដំណឹងទាំងអស់ រួមទាំងព័ត៌មានដូចជាទំនាក់ទំនង សារ និងរូបថត"</string> <string name="permission_storage" msgid="6831099350839392343">"រូបថត និងមេឌៀ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"សេវាកម្ម Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"សេវាកម្មនេះចែករំលែករូបថត មេឌៀ និងការជូនដំណឹងពីទូរសព្ទរបស់អ្នកទៅឧបករណ៍ផ្សេងទៀត"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"សេវាកម្មនេះចែករំលែករូបថត មេឌៀ និងការជូនដំណឹងពីទូរសព្ទរបស់អ្នកទៅឧបករណ៍ផ្សេងទៀត"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"អនុញ្ញាត"</string> <string name="consent_no" msgid="2640796915611404382">"កុំអនុញ្ញាត"</string> - <string name="consent_ok" msgid="3662376764371001106">"យល់ព្រម"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ផ្ទេរការអនុញ្ញាតកម្មវិធីទៅនាឡិការបស់អ្នក"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"ដើម្បីជួយឱ្យការរៀបចំនាឡិការបស់អ្នកកាន់តែងាយស្រួល កម្មវិធីដែលបានដំឡើងនៅលើនាឡិការបស់អ្នកអំឡុងពេលរៀបចំនឹងប្រើការអនុញ្ញាតដូចគ្នានឹងទូរសព្ទរបស់អ្នកដែរ។\n\n ការអនុញ្ញាតទាំងនេះអាចរួមបញ្ចូលសិទ្ធិចូលប្រើទីតាំង និងមីក្រូហ្វូនរបស់នាឡិកាអ្នក។"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml index 0d01ce7cdce7..7ba67a697640 100644 --- a/packages/CompanionDeviceManager/res/values-kn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"ಆ್ಯಪ್ಗಳು"</string> <string name="permission_apps_summary" msgid="798718816711515431">"ನಿಮ್ಮ ಫೋನ್ನ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string> <string name="title_app_streaming" msgid="2270331024626446950">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಫೋನ್ನಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ಕನೆಕ್ಟ್ ಆದಾಗ ಈ ಸಾಧನದಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾದ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರವೇಶಿಸುವುದಕ್ಕಾಗಿ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ಗೆ ರಿಮೋಟ್ ಪ್ರವೇಶವನ್ನು ಒದಗಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಸಾಧನ ಸೇವೆಗಳು"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ಈ ಸೇವೆಯನ್ನು ಬಳಸಲಾಗುತ್ತದೆ"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"ಅಧಿಸೂಚನೆಗಳು"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"ಒಪ್ಪಂದಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ಓದಬಹುದು"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"ಸಂಪರ್ಕಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ಓದಬಹುದು"</string> <string name="permission_storage" msgid="6831099350839392343">"ಫೋಟೋಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ಸೇವೆಗಳು"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ಈ ಸೇವೆಯು, ನಿಮ್ಮ ಫೋನ್ನಿಂದ ಇತರ ಸಾಧನಗಳಿಗೆ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತದೆ"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ಈ ಸೇವೆಯು, ನಿಮ್ಮ ಫೋನ್ನಿಂದ ಇತರ ಸಾಧನಗಳಿಗೆ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತದೆ"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"ಅನುಮತಿಸಿ"</string> <string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string> - <string name="consent_ok" msgid="3662376764371001106">"ಸರಿ"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ಆ್ಯಪ್ ಅನುಮತಿಗಳನ್ನು ನಿಮ್ಮ ವಾಚ್ಗೆ ವರ್ಗಾವಣೆ ಮಾಡಿ"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"ನಿಮ್ಮ ವಾಚ್ ಸೆಟಪ್ ಮಾಡುವುದನ್ನು ಸುಲಭವಾಗಿಸಲು, ಸೆಟಪ್ನ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ವಾಚ್ನಲ್ಲಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿದ ಆ್ಯಪ್ಗಳು, ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ ಬಳಸಿಕೊಳ್ಳುತ್ತವೆ.\n\n ಈ ಅನುಮತಿಗಳು ನಿಮ್ಮ ವಾಚ್ನ ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಸ್ಥಳದ ಪ್ರವೇಶವನ್ನು ಒಳಗೊಳ್ಳಬಹುದು."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index 2b98ce3875c6..3b4bc5c9d0a2 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"앱"</string> <string name="permission_apps_summary" msgid="798718816711515431">"휴대전화의 앱을 스트리밍합니다."</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"연결 시 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 이 휴대전화에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"연결 시 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 이 태블릿에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"연결 시 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 이 기기에 설치된 애플리케이션에 원격으로 액세스할 수 있는 권한을 제공하도록 허용합니다."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"이 서비스는 기기 간에 앱을 스트리밍하는 데 사용됩니다."</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"알림"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"연락처, 메시지, 사진 등의 정보를 포함한 모든 알림을 읽을 수 있습니다."</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"사진 및 미디어"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 서비스"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"이 서비스는 휴대전화의 사진, 미디어 및 알림을 다른 기기와 공유합니다."</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"이 서비스는 휴대전화의 사진, 미디어 및 알림을 다른 기기와 공유합니다."</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"허용"</string> <string name="consent_no" msgid="2640796915611404382">"허용 안함"</string> - <string name="consent_ok" msgid="3662376764371001106">"확인"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"앱 권한을 시계로 이전"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"시계를 더 쉽게 설정하기 위해 설정하는 동안 시계에 설치된 앱에서 휴대전화와 동일한 권한을 사용합니다.\n\n 이러한 권한에는 시계의 마이크 및 위치 정보에 대한 액세스가 포함될 수 있습니다."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml index 1f320dda3591..365116e4c8fb 100644 --- a/packages/CompanionDeviceManager/res/values-ky/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Колдонмолор"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Телефондогу колдонмолорду алып ойнотуу"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна Интернетке туташкан <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> телефонундагы колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна Интернетке туташкан <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> планшетиндеги колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна Интернетке туташкан <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> түзмөгүндөгү колдонмолорго алыстан кирүү мүмкүнчүлүгүн бериңиз."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Бул кызмат түзмөктөрүңүздүн ортосунда колдонмолорду тышкы экранга чыгаруу үчүн колдонулат"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Билдирмелер"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Бардык билдирмелерди, анын ичинде байланыштар, билдирүүлөр жана сүрөттөр сыяктуу маалыматты окуй алат"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Сүрөттөр жана медиа"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play кызматтары"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Бул кызмат сүрөттөрдү, медиа файлдарды жана билдирмелерди телефонуңуздан башка түзмөктөр менен бөлүшөт"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Бул кызмат сүрөттөрдү, медиа файлдарды жана билдирмелерди телефонуңуздан башка түзмөктөр менен бөлүшөт"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Уруксат берүү"</string> <string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string> - <string name="consent_ok" msgid="3662376764371001106">"Макул"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Колдонмонун уруксаттарын саатка өткөрүү"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Сааттын жөндөлүшүн жеңилдетүү үчүн жөндөө учурунда саатыңызга орнотулган колдонмолор телефонуңуздагы уруксаттарды колдонот.\n\n Мындай уруксаттарга саатыңыздын микрофонун же жайгашкан жерин колдонуу кириши мүмкүн."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml index debbf760fb17..29fcf2f39d09 100644 --- a/packages/CompanionDeviceManager/res/values-lo/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"ແອັບ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"ສະຕຣີມແອັບຂອງໂທລະສັບທ່ານ"</string> <string name="title_app_streaming" msgid="2270331024626446950">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ໃຫ້ສິດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ໂທລະສັບນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ໃຫ້ສິດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ແທັບເລັດນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ໃຫ້ສິດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ເພື່ອເຂົ້າເຖິງ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ຈາກໄລຍະໄກເພື່ອເຂົ້າເຖິງແອັບພລິເຄຊັນທີ່ຕິດຕັ້ງຢູ່ອຸປະກອນນີ້ເມື່ອເຊື່ອມຕໍ່ແລ້ວ."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ບໍລິການຂ້າມອຸປະກອນ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ບໍລິການນີ້ໃຊ້ເພື່ອສະຕຣີມແອັບລະຫວ່າງອຸປະກອນຂອງທ່ານ"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ອະນຸຍາດ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"ການແຈ້ງເຕືອນ"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"ສາມາດອ່ານການແຈ້ງເຕືອນທັງໝົດ, ຮວມທັງຂໍ້ມູນ ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່, ຂໍ້ຄວາມ ແລະ ຮູບພາບ"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ຮູບພາບ ແລະ ມີເດຍ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"ບໍລິການ Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ບໍລິການນີ້ຈະແບ່ງປັນຮູບພາບ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຈາກໂທລະສັບຂອງທ່ານໄປຫາອຸປະກອນອື່ນ"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ບໍລິການນີ້ຈະແບ່ງປັນຮູບພາບ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຈາກໂທລະສັບຂອງທ່ານໄປຫາອຸປະກອນອື່ນ"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"ອະນຸຍາດ"</string> <string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string> - <string name="consent_ok" msgid="3662376764371001106">"ຕົກລົງ"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ໂອນຍ້າຍການອະນຸຍາດແອັບໄປຫາໂມງຂອງທ່ານ"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"ເພື່ອເຮັດໃຫ້ຕັ້ງຄ່າໂມງຂອງທ່ານໄດ້ງ່າຍຂຶ້ນ, ແອັບທີ່ຕິດຕັ້ງຢູ່ໂມງຂອງທ່ານໃນລະຫວ່າງການຕັ້ງຄ່າຈະໃຊ້ການອະນຸຍາດດຽວກັນກັບໂທລະສັບຂອງທ່ານ.\n\n ການອະນຸຍາດເຫຼົ່ານີ້ອາດຮວມສິດເຂົ້າເຖິງໄມໂຄຣໂຟນ ແລະ ສະຖານທີ່ຂອງທ່ານນຳ."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml index 3904ad317acb..fad4a438d9d7 100644 --- a/packages/CompanionDeviceManager/res/values-lt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Programos"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Telefono programų perdavimas srautu"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šią informaciją iš jūsų telefono"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Leiskite <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prisijungus suteikti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> nuotolinę prieigą prie šiame telefone įdiegtų programų."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Leiskite <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prisijungus suteikti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> nuotolinę prieigą prie šiame planšetiniame kompiuteryje įdiegtų programų."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Leiskite <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prisijungus suteikti <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> nuotolinę prieigą prie šiame įrenginyje įdiegtų programų."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ši paslauga naudojama perduoti programas srautu tarp jūsų įrenginių"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Leisti <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pasiekti šią informaciją iš jūsų telefono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Pranešimai"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Galima skaityti visus pranešimus, įskaitant tokią informaciją kaip sutartys, pranešimai ir nuotraukos"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Nuotraukos ir medija"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"„Google Play“ paslaugos"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Naudojant šią paslaugą, telefone esančias nuotraukas, mediją ir pranešimus galima bendrinti su kitais įrenginiais"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Naudojant šią paslaugą, telefone esančias nuotraukas, mediją ir pranešimus galima bendrinti su kitais įrenginiais"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Leisti"</string> <string name="consent_no" msgid="2640796915611404382">"Neleisti"</string> - <string name="consent_ok" msgid="3662376764371001106">"Gerai"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Laikrodžio programų perkėlimo leidimai"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Kad būtų lengviau nustatyti laikrodį, jame atliekant sąranką įdiegtoms programoms bus naudojami tie patys leidimai kaip jūsų telefone.\n\n Šie leidimai gali apimti prieigą prie laikrodžio mikrofono ir vietovės."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml index 71bc79201f92..5562afb6228a 100644 --- a/packages/CompanionDeviceManager/res/values-lv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Lietotnes"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Var straumēt jūsu tālruņa lietotnes"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt šai informācijai no jūsu tālruņa"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> nodrošināt attālu piekļuvi tālrunim <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, lai piekļūtu šajā tālrunī instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> nodrošināt attālu piekļuvi planšetdatoram <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, lai piekļūtu šajā planšetdatorā instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> nodrošināt attālu piekļuvi ierīcei <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, lai piekļūtu šajā ierīcē instalētajām lietojumprogrammām, kamēr ir izveidots savienojums."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Vairāku ierīču pakalpojumi"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Šis pakalpojums tiek izmantots, lai straumētu lietotnes jūsu ierīcēs"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Atļaut lietotnei <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> piekļūt šai informācijai no jūsu tālruņa"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Paziņojumi"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Var lasīt visus paziņojumus, tostarp tādu informāciju kā kontaktpersonas, ziņojumus un fotoattēlus"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotoattēli un multivides faili"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play pakalpojumi"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Šis pakalpojums kopīgo fotoattēlus, multivides saturu un paziņojumus no jūsu tālruņa citās ierīcēs"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Šis pakalpojums kopīgo fotoattēlus, multivides saturu un paziņojumus no jūsu tālruņa citās ierīcēs"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Atļaut"</string> <string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string> - <string name="consent_ok" msgid="3662376764371001106">"Labi"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Lietotņu atļauju pārsūtīšana uz pulksteni"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Lai atvieglotu pulksteņa iestatīšanu, iestatīšanas laikā pulkstenī instalētās lietotnes saņems tādas pašas atļaujas, kādas tām ir tālrunī.\n\n Tostarp lietotnes var saņemt atļauju piekļūt pulksteņa mikrofonam un atrašanās vietai."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml index 851651f59a5f..bb198df233f6 100644 --- a/packages/CompanionDeviceManager/res/values-mk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Апликации"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Стримувајте ги апликациите на телефонот"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Овозможете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до овие податоци на телефонот"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да обезбеди далечински пристап на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> за да пристапува до апликации инсталирани на телефонов кога ќе се поврзе."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да обезбеди далечински пристап на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> за да пристапува до апликации инсталирани на таблетов кога ќе се поврзе."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да обезбеди далечински пристап на <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> за да пристапува до апликации инсталирани на уредов кога ќе се поврзе."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Услугава се користи за стриминг на апликации помеѓу вашите уреди"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Овозможете <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да пристапува до овие податоци на телефонот"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Известувања"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"може да ги чита сите известувања, вклучително и податоци како договори, пораки и фотографии"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"може да ги чита сите известувања, вклучително и податоци како контакти, пораки и фотографии"</string> <string name="permission_storage" msgid="6831099350839392343">"Аудиовизуелни содржини"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Услуги на Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Услугава споделува фотографии, аудиовизуелни содржини и известувања од вашиот телефон на други уреди"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Услугава споделува фотографии, аудиовизуелни содржини и известувања од вашиот телефон на други уреди"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string> <string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string> - <string name="consent_ok" msgid="3662376764371001106">"Во ред"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Префрлете ги дозволите за апликациите на вашиот часовник"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"За полесно поставувањето на часовникот, апликациите инсталирани на часовникот при поставувањето ќе ги користат истите дозволи како на телефонот.\n\n Овие дозволи може да опфаќаат пристап до микрофонот и локацијата на часовникот."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml index 9e330e64c0e4..b8c44a5a635e 100644 --- a/packages/CompanionDeviceManager/res/values-ml/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"ആപ്പുകൾ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"നിങ്ങളുടെ ഫോണിലെ ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ"</string> <string name="title_app_streaming" msgid="2270331024626446950">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ആപ്പിനെ അനുവദിക്കുക"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"കണക്റ്റ് ചെയ്യുമ്പോൾ, ഈ ഫോണിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ആക്സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്സസ് <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> എന്നതിന് നൽകാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"കണക്റ്റ് ചെയ്യുമ്പോൾ, ഈ ടാബ്ലെറ്റിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ആക്സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്സസ് <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> എന്നതിന് നൽകാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"കണക്റ്റ് ചെയ്യുമ്പോൾ, ഈ ഉപകരണത്തിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ആക്സസ് ചെയ്യാനുള്ള റിമോട്ട് ആക്സസ് <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> എന്നതിന് നൽകാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> എന്നതിനെ അനുവദിക്കുക."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ക്രോസ്-ഉപകരണ സേവനങ്ങൾ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"നിങ്ങളുടെ ഉപകരണങ്ങൾക്കിടയിൽ ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ ഈ സേവനം ഉപയോഗിക്കുന്നു"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്സസ് ചെയ്യാൻ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ആപ്പിനെ അനുവദിക്കുക"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"അറിയിപ്പുകൾ"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"കോൺടാക്റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഉൾപ്പെടെ, എല്ലാ അറിയിപ്പുകളും വായിക്കാനാകും"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"കോൺടാക്റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ മുതലായ വിവരങ്ങൾ ഉൾപ്പെടെയുള്ള എല്ലാ അറിയിപ്പുകളും വായിക്കാനാകും"</string> <string name="permission_storage" msgid="6831099350839392343">"ഫോട്ടോകളും മീഡിയയും"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play സേവനങ്ങൾ"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ഈ സേവനം നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഫോട്ടോകളും മീഡിയയും അറിയിപ്പുകളും മറ്റ് ഉപകരണങ്ങളിലേക്ക് അയയ്ക്കുന്നു"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ഈ സേവനം നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഫോട്ടോകളും മീഡിയയും അറിയിപ്പുകളും മറ്റ് ഉപകരണങ്ങളിലേക്ക് അയയ്ക്കുന്നു"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"അനുവദിക്കുക"</string> <string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string> - <string name="consent_ok" msgid="3662376764371001106">"ശരി"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"നിങ്ങളുടെ വാച്ചിലേക്ക് ആപ്പ് അനുമതികൾ കൈമാറുക"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"നിങ്ങളുടെ വാച്ച് സജ്ജീകരിക്കുന്നത് എളുപ്പമാക്കാൻ, സജ്ജീകരിക്കുമ്പോൾ ഫോണിലുള്ള അതേ അനുമതികൾ നിങ്ങളുടെ വാച്ചിൽ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ആപ്പുകൾ ഉപയോഗിക്കും.\n\n ഈ അനുമതികളിൽ നിങ്ങളുടെ വാച്ചിന്റെ മൈക്രോഫോണിലേക്കും ലോക്കേഷനിലേക്കുമുള്ള ആക്സസ് ഉൾപ്പെട്ടേക്കാം."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml index 00c032d4aa18..7233c04954f4 100644 --- a/packages/CompanionDeviceManager/res/values-mn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Аппууд"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Таны утасны аппуудыг дамжуулах"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г холбогдсон үед энэ утсанд суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г холбогдсон үед энэ таблетад суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>-г холбогдсон үед энэ төхөөрөмжид суулгасан аппуудад хандахын тулд алсын хандалт өгөхийг зөвшөөрнө үү."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Энэ үйлчилгээг таны төхөөрөмжүүд хооронд аппууд дамжуулахад ашигладаг"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Мэдэгдэл"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Гэрээ, мессеж болон зураг зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших боломжтой"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Харилцагчид, мессеж болон зураг зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших боломжтой"</string> <string name="permission_storage" msgid="6831099350839392343">"Зураг болон медиа"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play үйлчилгээ"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Энэ үйлчилгээ зураг, медиа болон мэдэгдлийг таны утаснаас бусад төхөөрөмж рүү хуваалцана"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Энэ үйлчилгээ зураг, медиа болон мэдэгдлийг таны утаснаас бусад төхөөрөмж рүү хуваалцана"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Зөвшөөрөх"</string> <string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Цагандаа аппын зөвшөөрлийг шилжүүлэх"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Таны цагийг тохируулахад илүү хялбар болгохын тулд тохируулгын үеэр таны цаган дээр суулгасан аппууд нь утастай тань ижил зөвшөөрлийг ашиглана.\n\n Эдгээр зөвшөөрөлд таны цагийн микрофон болон байршлын хандалт зэрэг багтаж магадгүй."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml index 303b141a72e4..d2aa48ca7cbc 100644 --- a/packages/CompanionDeviceManager/res/values-mr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"ॲप्स"</string> <string name="permission_apps_summary" msgid="798718816711515431">"फोनवरील ॲप्स स्ट्रीम करा"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला ही माहिती तुमच्या फोनवरून अॅक्सेस करण्यासाठी अनुमती द्या"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"कनेक्ट केलेले असताना या फोनवरील अॅप्लिकेशन अॅक्सेस करता यावीत यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> चा रिमोट अॅक्सेस द्या."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"कनेक्ट केलेले असताना या टॅबलेटवरील अॅप्लिकेशन अॅक्सेस करता यावीत यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> चा रिमोट अॅक्सेस द्या."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"कनेक्ट केलेले असताना या डिव्हाइसवरील अॅप्लिकेशन अॅक्सेस करता यावीत यासाठी <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> चा रिमोट अॅक्सेस द्या."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिव्हाइस सेवा"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ही सेवा तुमच्या डिव्हाइस दरम्यान अॅप्स स्ट्रीम करण्यासाठी वापरली जाते"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ला ही माहिती तुमच्या फोनवरून अॅक्सेस करण्यासाठी अनुमती द्या"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"सूचना"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"करार, मेसेज आणि फोटो यांसारख्या माहितीच्या समावेशासह सर्व सूचना वाचू शकते"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"संपर्क, मेसेज आणि फोटो यांसारख्या माहितीचा समावेश असलेल्या सर्व सूचना वाचू शकते"</string> <string name="permission_storage" msgid="6831099350839392343">"फोटो आणि मीडिया"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवा"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ही सेवा तुमच्या फोनवरून इतर डिव्हाइसवर फोटो, मीडिया आणि सूचना शेअर करते"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ही सेवा तुमच्या फोनवरून इतर डिव्हाइसवर फोटो, मीडिया आणि सूचना शेअर करते"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"अनुमती द्या"</string> <string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string> - <string name="consent_ok" msgid="3662376764371001106">"ओके"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"अॅप परवानग्या तुमच्या वॉचवर ट्रान्सफर करा"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"तुमचे वॉच सेट करणे आणखी सोपे करण्यासाठी, सेटअपदरम्यान तुमच्या वॉचवर इंस्टॉल केलेली ॲप्स ही तुमच्या फोनप्रमाणेच परवानग्या वापरतील.\n\n या परवानग्यांमध्ये तुमच्या वॉचचा मायक्रोफोन आणि स्थानाच्या अॅक्सेसचा समावेश असू शकतो."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml index e234089857d5..efc7412b03d0 100644 --- a/packages/CompanionDeviceManager/res/values-ms/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apl"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Strim apl telefon anda"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses maklumat ini daripada telefon anda"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Membenarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberi akses jauh kepada <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> untuk mengakses aplikasi yang dipasang pada telefon ini apabila disambungkan."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Membenarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberi akses jauh kepada <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> untuk mengakses aplikasi yang dipasang pada tablet ini apabila disambungkan."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Membenarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> memberi akses jauh kepada <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> untuk mengakses aplikasi yang dipasang pada peranti ini apabila disambungkan."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Perkhidmatan ini digunakan untuk menstrim apl antara peranti anda"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Benarkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses maklumat ini daripada telefon anda"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Pemberitahuan"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Boleh membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Boleh membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Perkhidmatan Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Perkhidmatan ini berkongsi foto, media dan pemberitahuan daripada telefon anda kepada peranti lain"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Perkhidmatan ini berkongsi foto, media dan pemberitahuan daripada telefon anda kepada peranti lain"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Benarkan"</string> <string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Pindahkan kebenaran apl pada jam tangan anda"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Untuk memudahkan penyediaan jam tangan anda, apl yang dipasang pada jam tangan anda semasa persediaan akan menggunakan kebenaran yang sama seperti telefon anda.\n\n Kebenaran ini mungkin termasuk akses kepada mikrofon dan lokasi jam tangan anda."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml index 61a60b20fc33..ed678c90ea18 100644 --- a/packages/CompanionDeviceManager/res/values-my/strings.xml +++ b/packages/CompanionDeviceManager/res/values-my/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"အက်ပ်များ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"သင့်ဖုန်းရှိအက်ပ်များကို တိုက်ရိုက်လွှင့်နိုင်သည်"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ချိတ်ဆက်ထားသည့်အခါ ဤဖုန်းတွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အားခွင့်ပြုပါ။"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ချိတ်ဆက်ထားသည့်အခါ ဤတက်ဘလက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အားခွင့်ပြုပါ။"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ချိတ်ဆက်ထားသည့်အခါ ဤစက်တွင် ထည့်သွင်းထားသော အပလီကေးရှင်းများကို သုံးခွင့်ရရန်အတွက် <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ကိုအဝေးမှ သုံးခွင့်ပေးနိုင်ရန် <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> အားခွင့်ပြုပါ။"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"စက်များကြားသုံး ဝန်ဆောင်မှုများ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"သင့်စက်များကြား အက်ပ်များ တိုက်ရိုက်လွှင့်ရန် ဤဝန်ဆောင်မှုကို အသုံးပြုသည်"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"အကြောင်းကြားချက်များ"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ဓာတ်ပုံနှင့် မီဒီယာများ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ဝန်ဆောင်မှုများ"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ဤဝန်ဆောင်မှုသည် ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များကို သင့်ဖုန်းမှ အခြားစက်များသို့ မျှဝေသည်"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ဤဝန်ဆောင်မှုသည် ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များကို သင့်ဖုန်းမှ အခြားစက်များသို့ မျှဝေသည်"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"ခွင့်ပြုရန်"</string> <string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"သင်၏နာရီသို့ အက်ပ်ခွင့်ပြုချက်များ လွှဲပြောင်းရန်"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"သင်၏နာရီ စနစ်ထည့်သွင်းရာတွင် ပိုလွယ်ကူစေရန် စနစ်ထည့်သွင်းနေစဉ်အတွင်း နာရီတွင်ထည့်သွင်းသော အက်ပ်များသည် သင့်ဖုန်းနှင့် အလားတူခွင့်ပြုချက်များကို သုံးပါမည်။\n\n ဤခွင့်ပြုချက်များတွင် သင့်နာရီ၏ မိုက်ခရိုဖုန်းနှင့် တည်နေရာတို့ကို သုံးခွင့် ပါဝင်နိုင်သည်။"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml index 078a2d4a64cf..40caa2352c1d 100644 --- a/packages/CompanionDeviceManager/res/values-nb/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Apper"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Strøm appene på telefonen"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gir <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ekstern tilgang til apper som er installert på denne telefonen, når den er koblet til internett."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gir <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ekstern tilgang til apper som er installert på dette nettbrettet, når det er koblet til internett."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Tillat at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gir <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ekstern tilgang til apper som er installert på denne enheten, når den er koblet til internett."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Denne tjenesten brukes til å strømme apper mellom enhetene dine"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Varsler"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kan lese alle varsler, inkludert informasjon som kontrakter, meldinger og bilder"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Bilder og medier"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Denne tjenesten deler bilder, medier og varsler fra telefonen din til andre enheter"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Denne tjenesten deler bilder, medier og varsler fra telefonen din til andre enheter"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Tillat"</string> <string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Overfør apptillatelser til klokken din"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"For å gjøre det enklere å konfigurere klokken din bruker apper som installeres på klokken under konfigureringen, samme tillatelser som på telefonen.\n\n Disse tillatelsene kan inkludere tilgang til mikrofonen på klokken og posisjon."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml index fd8a6cf23ba7..2a27219275a6 100644 --- a/packages/CompanionDeviceManager/res/values-ne/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"एपहरू"</string> <string name="permission_apps_summary" msgid="798718816711515431">"आफ्नो फोनका एपहरू प्रयोग गर्नुहोस्"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई यो फोनमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई यो ट्याब्लेटमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"यो डिभाइस इन्टरनेटमा कनेक्ट भएका बेला, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> लाई यो डिभाइसमा इन्स्टल गरिएका एप टाढैबाट प्रयोग गर्ने अनुमति दिन दिनुहोस्।"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रस-डिभाइस सेवाहरू"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"यो सेवा तपाईंको एउटा डिभाइसबाट अर्को डिभाइसमा एपहरू स्ट्रिम गर्न प्रयोग गरिन्छ"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"सूचनाहरू"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"कन्ट्याक्ट, म्यासेज र फोटोलगायतका व्यक्तिगत जानकारीसहित तपाईंका सूचनाहरू पढ्न सक्छ"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"कन्ट्याक्ट, म्यासेज र फोटोलगायतका जानकारीसहित सबै सूचनाहरू पढ्न सक्छ"</string> <string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"यो सेवाले तपाईंको फोनबाट अन्य डिभाइसमा फोटो, मिडिया र सूचनाहरू सेयर गर्छ"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"यो सेवाले तपाईंको फोनबाट अन्य डिभाइसमा फोटो, मिडिया र सूचनाहरू सेयर गर्छ"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"अनुमति दिनुहोस्"</string> <string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string> - <string name="consent_ok" msgid="3662376764371001106">"ठिक छ"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"एपलाई दिइएका अनुमति घडीमा ट्रान्स्फर गर्नुहोस्"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"तपाईंको घडी सेटअप गर्ने कार्य सजिलो बनाउनका लागि सेटअप गर्ने क्रममा तपाईंको घडीमा इन्स्टल गरिएका एपहरूले पनि तपाईंको फोनमा दिइएको जस्तै अनुमति प्रयोग गर्ने छन्।\n\n यी अनुमतिमा तपाईंको घडीको माइक्रोफोन र लोकेसन प्रयोग गर्ने जस्ता अनुमति पर्न सक्छन्।"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml index 76ec957ebf73..3b27f9dc6deb 100644 --- a/packages/CompanionDeviceManager/res/values-nl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"De apps van je telefoon streamen"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Toestaan dat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> als er verbinding is <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> externe toegang geeft tot apps die zijn geïnstalleerd op deze telefoon."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Toestaan dat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> als er verbinding is <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> externe toegang geeft tot apps die zijn geïnstalleerd op deze tablet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Toestaan dat <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> als er verbinding is <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> externe toegang geeft tot apps die zijn geïnstalleerd op dit apparaat."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Met deze service kun je apps streamen tussen je apparaten"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> toegang geven tot deze informatie op je telefoon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Meldingen"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kan alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string> <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Met deze service kun je foto\'s, media en meldingen vanaf je telefoon met andere apparaten delen"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Met deze service kun je foto\'s, media en meldingen vanaf je telefoon met andere apparaten delen"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Toestaan"</string> <string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"App-rechten overzetten naar je horloge"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"We willen het makkelijker voor je maken om je horloge in te stellen. Daarom gebruiken apps die tijdens het instellen worden geïnstalleerd op je horloge, dezelfde rechten als op je telefoon.\n\n Deze rechten kunnen toegang tot de microfoon en locatie van je horloge omvatten."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml index 6b6649290802..3849f31f9f09 100644 --- a/packages/CompanionDeviceManager/res/values-or/strings.xml +++ b/packages/CompanionDeviceManager/res/values-or/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"ଆପ୍ସ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"ଆପଣଙ୍କ ଫୋନର ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରନ୍ତୁ"</string> <string name="title_app_streaming" msgid="2270331024626446950">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ, ଏହି ଫୋନଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ, ଏହି ଟାବଲେଟଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ, ଏହି ଡିଭାଇସଟି ସଂଯୁକ୍ତ ହୋଇଥିବା ବେଳେ ଏଥିରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପ୍ଲିକେସନଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>କୁ ରିମୋଟ ଆକ୍ସେସ ପ୍ରଦାନ କରିବାକୁ ଦିଅନ୍ତୁ।"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"କ୍ରସ-ଡିଭାଇସ ସେବାଗୁଡ଼ିକ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ ଏହି ସେବାକୁ ବ୍ୟବହାର କରାଯାଏ"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"ଯୋଗାଯୋଗ, ମେସେଜ ଏବଂ ଫଟୋଗୁଡ଼ିକ ପରି ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତିକୁ ପଢ଼ିପାରିବ"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ଫଟୋ ଏବଂ ମିଡିଆ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ସେବାଗୁଡ଼ିକ"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ଏହି ସେବା ଆପଣଙ୍କ ଫୋନରୁ ଅନ୍ୟ ଡିଭାଇସଗୁଡ଼ିକୁ ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତି ସେୟାର କରେ"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ଏହି ସେବା ଆପଣଙ୍କ ଫୋନରୁ ଅନ୍ୟ ଡିଭାଇସଗୁଡ଼ିକୁ ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତି ସେୟାର କରେ"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"ଅନୁମତି ଦିଅନ୍ତୁ"</string> <string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string> - <string name="consent_ok" msgid="3662376764371001106">"ଠିକ୍ ଅଛି"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ଆପଣଙ୍କ ୱାଚକୁ ଆପ ଅନୁମତିଗୁଡ଼ିକ ଟ୍ରାନ୍ସଫର କରନ୍ତୁ"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"ଆପଣଙ୍କ ୱାଚ ସେଟ ଅପ କରିବାକୁ ସହଜ କରିବା ପାଇଁ, ସେଟଅପ ସମୟରେ ଆପଣଙ୍କର ୱାଚରେ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପଗୁଡ଼ିକ ଆପଣଙ୍କ ଫୋନରେ ଥିବା ଆପଗୁଡ଼ିକ ପରି ସମାନ ଅନୁମତିଗୁଡ଼ିକ ବ୍ୟବହାର କରିବ।\n\n ଏହି ଅନୁମତିଗୁଡ଼ିକରେ ଆପଣଙ୍କ ୱାଚର ମାଇକ୍ରୋଫୋନ ଏବଂ ଲୋକେସନକୁ ଆକ୍ସେସ ଅନ୍ତର୍ଭୁକ୍ତ ହୋଇପାରେ।"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml index 93b018e3e54e..432f2b906bf2 100644 --- a/packages/CompanionDeviceManager/res/values-pa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"ਐਪਾਂ"</string> <string name="permission_apps_summary" msgid="798718816711515431">"ਆਪਣੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰੋ"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਫ਼ੋਨ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਟੈਬਲੈੱਟ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"ਕਨੈਕਟ ਹੋਣ \'ਤੇ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਥਾਪਤ ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ਨੂੰ ਰਿਮੋਟ ਪਹੁੰਚ ਮੁਹੱਈਆ ਕਰਵਾਉਣ ਦਿਓ।"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"ਇਸ ਸੇਵਾ ਦੀ ਵਰਤੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"ਸੂਚਨਾਵਾਂ"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"ਤੁਸੀਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਪੜ੍ਹ ਸਕਦੇ ਹੋ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਸੰਪਰਕਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਫ਼ੋਟੋਆਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ਸੇਵਾਵਾਂ"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ਇਹ ਸੇਵਾ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਹੋਰ ਡੀਵਾਈਸਾਂ \'ਤੇ ਸਾਂਝਾ ਕਰਦੀ ਹੈ"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ਇਹ ਸੇਵਾ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਹੋਰ ਡੀਵਾਈਸਾਂ \'ਤੇ ਸਾਂਝਾ ਕਰਦੀ ਹੈ"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"ਇਜਾਜ਼ਤ ਦਿਓ"</string> <string name="consent_no" msgid="2640796915611404382">"ਇਜਾਜ਼ਤ ਨਾ ਦਿਓ"</string> - <string name="consent_ok" msgid="3662376764371001106">"ਠੀਕ ਹੈ"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ਐਪ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਆਪਣੀ ਘੜੀ \'ਤੇ ਟ੍ਰਾਂਸਫ਼ਰ ਕਰੋ"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"ਤੁਹਾਡੀ ਘੜੀ ਦਾ ਸੈੱਟਅੱਪ ਕਰਨਾ ਆਸਾਨ ਬਣਾਉਣ ਲਈ, ਤੁਹਾਡੀ ਘੜੀ \'ਤੇ ਸਥਾਪਤ ਐਪਾਂ ਸੈੱਟਅੱਪ ਦੌਰਾਨ ਉਹੀ ਇਜਾਜ਼ਤਾਂ ਵਰਤਣਗੀਆਂ ਜੋ ਤੁਹਾਡਾ ਫ਼ੋਨ ਵਰਤਦਾ ਹੈ।\n\n ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਵਿੱਚ ਤੁਹਾਡੀ ਘੜੀ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ।"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml index a15af4b51dfb..a51c69672f83 100644 --- a/packages/CompanionDeviceManager/res/values-pl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikacje"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Odtwarzaj strumieniowo aplikacje z telefonu"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Zezwól na zapewnianie przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zdalnego dostępu do aplikacji zainstalowanych na telefonie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> po połączeniu jej z tym telefonem."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Zezwól na zapewnianie przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zdalnego dostępu do aplikacji zainstalowanych na tablecie <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> po połączeniu jej z tym tabletem."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Zezwól na zapewnianie przez aplikację <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> zdalnego dostępu do aplikacji zainstalowanych na urządzeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> po połączeniu jej z urządzeniem."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ta usługa jest używana do strumieniowego odtwarzania danych z aplikacji między urządzeniami"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Zezwól aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Powiadomienia"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Może odczytywać wszystkie powiadomienia, w tym informacje takie jak kontakty, wiadomości i zdjęcia"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Zdjęcia i multimedia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Usługi Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ta usługa udostępnia zdjęcia, multimedia i powiadomienia z telefonu innym urządzeniom"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ta usługa udostępnia zdjęcia, multimedia i powiadomienia z telefonu innym urządzeniom"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Zezwól"</string> <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Przenieś uprawnienia aplikacji na zegarek"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Aby łatwiej było skonfigurować zegarek, aplikacje zainstalowane na nim podczas konfiguracji będą korzystały z tych samych uprawnień co telefon.\n\n Może to oznaczać dostęp do mikrofonu i lokalizacji na zegarku."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml index 7d2282371d39..7cd3a37d0f34 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este serviço é usado para fazer streaming de apps entre seus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificações"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml index e0c717c1f9ff..de412ebc9df0 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Faça stream das apps do telemóvel"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> forneça acesso remoto ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> para aceder a aplicações instaladas neste telemóvel quando estiver ligado."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> forneça acesso remoto ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> para aceder a aplicações instaladas neste tablet quando estiver ligado."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> forneça acesso remoto ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> para aceder a aplicações instaladas neste dispositivo quando estiver ligado."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este serviço é utilizado para fazer stream de apps entre os seus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificações"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificações, incluindo informações como contratos, mensagens e fotos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contratos, mensagens e fotos"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos e multimédia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este serviço partilha fotos, conteúdo multimédia e notificações do seu telemóvel para outros dispositivos"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este serviço partilha fotos, conteúdo multimédia e notificações do seu telemóvel para outros dispositivos"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfira as autorizações da app para o seu relógio"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do seu relógio, as apps instaladas no mesmo durante a configuração utilizarão as mesmas autorizações que o telemóvel.\n\n Estas autorizações podem incluir o acesso ao microfone e à localização do seu relógio."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml index 7d2282371d39..7cd3a37d0f34 100644 --- a/packages/CompanionDeviceManager/res/values-pt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Apps"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Faça streaming dos apps do seu smartphone"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no smartphone quando ele estiver conectado."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no tablet quando ele estiver conectado."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Permita que o app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> conceda ao <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> acesso remoto aos aplicativos instalados no dispositivo quando ele estiver conectado."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Este serviço é usado para fazer streaming de apps entre seus dispositivos"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse essas informações do smartphone"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificações"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Este serviço compartilha fotos, mídia e notificações do seu smartphone para outros dispositivos"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permitir"</string> <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferir as permissões de apps para o relógio"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Para facilitar a configuração do relógio, os apps instalados nele durante a configuração vão usar as mesmas permissões que o smartphone.\n\n Essas permissões podem incluir acesso ao microfone ou à localização do relógio."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml index 61b47fbb7d71..7e51104adbbc 100644 --- a/packages/CompanionDeviceManager/res/values-ro/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplicații"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Să redea în stream aplicațiile telefonului"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Permiteți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze aceste informații de pe telefon"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lăsați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să ofere acces la distanță pentru <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ca să se poată accesa aplicațiile instalate pe acest telefon când se conectează utilizatorul."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lăsați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să ofere acces la distanță pentru <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ca să se poată accesa aplicațiile instalate pe această tabletă când se conectează utilizatorul."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lăsați <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să ofere acces la distanță pentru <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ca să se poată accesa aplicațiile instalate pe acest dispozitiv când se conectează utilizatorul."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Acest serviciu se folosește pentru a proiecta aplicații între dispozitive"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Permiteți ca <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> să acceseze aceste informații de pe telefon"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Notificări"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Poate să citească toate notificările, inclusiv informații cum ar fi contracte, mesaje și fotografii"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotografii și media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Servicii Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Serviciul trimite fotografii, conținut media și notificări de pe telefon pe alte dispozitive"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Serviciul trimite fotografii, conținut media și notificări de pe telefon pe alte dispozitive"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Permiteți"</string> <string name="consent_no" msgid="2640796915611404382">"Nu permiteți"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferați permisiunile pentru aplicații pe ceas"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Ca să configurați mai ușor ceasul, aplicațiile instalate pe ceas în timpul procesului de configurare vor folosi aceleași permisiuni ca telefonul.\n\n Între acestea se poate număra accesul la microfonul și locația ceasului."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml index 062314f337b6..2fa1073551e1 100644 --- a/packages/CompanionDeviceManager/res/values-ru/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Трансляция приложений с телефона."</string> <string name="title_app_streaming" msgid="2270331024626446950">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> получать эту информацию с вашего телефона"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> при наличии подключения предоставить устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> удаленный доступ к приложениям, установленным на этом телефоне."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> при наличии подключения предоставить устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> удаленный доступ к приложениям, установленным на этом планшете."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> при наличии подключения предоставить устройству <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> удаленный доступ к приложениям, установленным на этом устройстве."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Этот сервис используется для трансляции приложений с одного устройства на другое."</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> получать эту информацию с вашего телефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Уведомления"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Чтение всех уведомлений, в том числе сведений о контактах, сообщениях и фотографиях."</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Фотографии и медиафайлы"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Сервисы Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Этот сервис используется для отправки фотографий, медиафайлов и уведомлений с вашего телефона на другие устройства."</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Этот сервис используется для отправки фотографий, медиафайлов и уведомлений с вашего телефона на другие устройства."</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Разрешить"</string> <string name="consent_no" msgid="2640796915611404382">"Запретить"</string> - <string name="consent_ok" msgid="3662376764371001106">"ОК"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перенос разрешений для приложений на часы"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Для приложений, установленных на часы во время настройки, будут использоваться те же разрешения, что и на телефоне.\n\n Например, может быть включен доступ к микрофону на часах или сведениям о местоположении."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml index 65f7865d4671..6bb3c0905cda 100644 --- a/packages/CompanionDeviceManager/res/values-si/strings.xml +++ b/packages/CompanionDeviceManager/res/values-si/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"යෙදුම්"</string> <string name="permission_apps_summary" msgid="798718816711515431">"ඔබගේ දුරකථනයේ යෙදුම් ප්රවාහ කරන්න"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්රවේශ වීමට ඉඩ දෙන්න"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"සම්බන්ධ වූ විට මෙම දුරකථනයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්රවේශ වීමට <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> හට දුරස්ථ ප්රවේශය ලබා දීමට ඉඩ දෙන්න."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"සම්බන්ධ වූ විට මෙම ටැබ්ලටයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්රවේශ වීමට <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> හට දුරස්ථ ප්රවේශය ලබා දීමට ඉඩ දෙන්න."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"සම්බන්ධ වූ විට මෙම උපාංගයේ ස්ථාපනය කර ඇති යෙදුම් වෙත ප්රවේශ වීමට <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> හට දුරස්ථ ප්රවේශය ලබා දීමට ඉඩ දෙන්න."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"හරස්-උපාංග සේවා"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"මෙම සේවාව ඔබගේ උපාංග අතර යෙදුම් ප්රවාහ කිරීමට භාවිත වේ"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්රවේශ වීමට ඉඩ දෙන්න"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"දැනුම්දීම්"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"ගිවිසුම්, පණිවිඩ සහ ඡායාරූප වැනි තොරතුරු ඇතුළුව සියලු දැනුම්දීම් කියවිය හැකිය"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ඡායාරූප සහ මාධ්ය"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play සේවා"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"මෙම සේවාව ඔබගේ දුරකථනයෙන් වෙනත් උපාංග වෙත ඡායාරූප, මාධ්ය සහ දැනුම්දීම් බෙදා ගනී"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"මෙම සේවාව ඔබගේ දුරකථනයෙන් වෙනත් උපාංග වෙත ඡායාරූප, මාධ්ය සහ දැනුම්දීම් බෙදා ගනී"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"ඉඩ දෙන්න"</string> <string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string> - <string name="consent_ok" msgid="3662376764371001106">"හරි"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ඔබගේ ඔරලෝසුවට යෙදුම් අවසර මාරු කිරීම"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"ඔබගේ ඔරලෝසුව පිහිටුවීම පහසු කිරීමට, පිහිටුවීමේදී ඔබගේ ඔරලෝසුවේ ස්ථාපනය කර ඇති යෙදුම් ඔබගේ දුරකථනයට සමාන අවසර භාවිත කරනු ඇත.\n\n මෙම අවසරවලට ඔබගේ ඔරලෝසුවේ මයික්රෆෝනයට සහ ස්ථානයට ප්රවේශය ඇතුළත් විය හැකිය."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml index 167eac8c8fdc..878d26461a49 100644 --- a/packages/CompanionDeviceManager/res/values-sk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikácie"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikácie telefónu"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> vzdialený prístup k telefónu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> vzdialený prístup k tabletu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> vzdialený prístup k zariadeniu <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>, aby mala po pripojení prístup k aplikáciám, ktoré sú v ňom nainštalované."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Pomocou tejto služby sa streamujú aplikácie medzi vašimi zariadeniami"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Upozornenia"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Môže čítať všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Môže čítať všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string> <string name="permission_storage" msgid="6831099350839392343">"Fotky a médiá"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Táto služba zdieľa fotky, médiá a upozornenia z vášho telefónu do iných zariadení"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Táto služba zdieľa fotky, médiá a upozornenia z vášho telefónu do iných zariadení"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Povoliť"</string> <string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Presun povolení aplikácie do hodiniek"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"V rámci zjednodušenia nastavenia hodiniek budú aplikácie nainštalované do hodiniek pri nastavovaní používať rovnaké povolenia ako váš telefón.\n\n Tieto povolenia môžu zahrnovať prístup k mikrofónu a polohe hodiniek."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml index 5b795826c42d..0734ee1ff271 100644 --- a/packages/CompanionDeviceManager/res/values-sl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Pretočno predvajanje aplikacij telefona"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu."</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoli oddaljen dostop do telefona <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> za dostop do aplikacij, nameščenih v tem telefonu, ko je povezan v internet."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoli oddaljen dostop do tabličnega računalnika <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> za dostop do aplikacij, nameščenih v tem tabličnem računalniku, ko je povezan v internet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovoli oddaljen dostop do naprave <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> za dostop do aplikacij, nameščenih v tej napravi, ko je povezana v internet."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ta storitev se uporablja za pretočno predvajanje aplikacij med napravami."</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu."</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Obvestila"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Lahko bere vsa obvestila, vključno s podatki, kot so pogodbe, sporočila in fotografije."</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Lahko bere vsa obvestila, vključno s podatki, kot so stiki, sporočila in fotografije."</string> <string name="permission_storage" msgid="6831099350839392343">"Fotografije in predstavnost"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Storitve Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ta storitev deli fotografije, predstavnost in obvestila v telefonu z drugimi napravami."</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ta storitev deli fotografije, predstavnost in obvestila v telefonu z drugimi napravami."</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Dovoli"</string> <string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string> - <string name="consent_ok" msgid="3662376764371001106">"V redu"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Prenos dovoljenj za aplikacije v uro"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Za lažjo nastavitev ure bodo aplikacije, ki so bile med nastavljanjem nameščene v uri, uporabljale enaka dovoljenja kot tiste v telefonu.\n\n Ta dovoljenja lahko vključujejo dostop do mikrofona in lokacije ure."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml index b69fa8afd092..5ae176472b8f 100644 --- a/packages/CompanionDeviceManager/res/values-sq/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Aplikacionet"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Transmeto aplikacionet e telefonit tënd"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ofrojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë telefon kur lidhet."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ofrojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë tablet kur lidhet."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> t\'i ofrojë <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> qasje në distancë për të pasur qasje në aplikacionet e instaluara në këtë pajisje kur lidhet."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ky shërbim përdoret për të transmetuar aplikacione mes pajisjeve të tua"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Njoftimet"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Mund të lexojë të gjitha njoftimet, duke përfshirë informacione si kontaktet, mesazhet dhe fotografitë"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotografitë dhe media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ky shërbim ndan fotografitë, median dhe njoftimet nga telefoni yt te pajisjet e tjera"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ky shërbim ndan fotografitë, median dhe njoftimet nga telefoni yt te pajisjet e tjera"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string> <string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string> - <string name="consent_ok" msgid="3662376764371001106">"Në rregull"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transfero lejet e aplikacionit te ora jote"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Për ta bërë më të lehtë konfigurimin e orës, aplikacionet e instaluara në orën tënde gjatë konfigurimit do të përdorin të njëjtat leje si telefoni yt.\n\n Këto leje mund të përfshijnë qasje në mikrofonin dhe vendndodhjen e orës."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml index d40a11295833..1d4e036fc445 100644 --- a/packages/CompanionDeviceManager/res/values-sr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Апликације"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Стримујте апликације на телефону"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа овим информацијама са телефона"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да даљински приступа апликацијама инсталираним на телефону <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> када је повезан."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да даљински приступа апликацијама инсталираним на таблету <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> када је повезан."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозволите апликацији <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да даљински приступа апликацијама инсталираним на уређају <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> када је повезан."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ова услуга се користи за стримовање апликација између уређаја"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Дозволите да <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> приступа овим информацијама са телефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Обавештења"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Може да чита сва обавештења, укључујући информације попут уговора, порука и слика"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Слике и медији"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play услуге"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Ова услуга дели слике, медијски садржај и обавештења са телефона на друге уређаје"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Ова услуга дели слике, медијски садржај и обавештења са телефона на друге уређаје"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Дозволи"</string> <string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string> - <string name="consent_ok" msgid="3662376764371001106">"Потврди"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Пренесите дозволе за апликације на сат"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Да бисмо поједноставили подешавање сата, апликације инсталиране на сату током подешавања ће користити исте дозволе као телефон.\n\n Те дозволе могу да обухватају приступ микрофону и локацији сата."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml index fff01ed727c9..4e85534adb53 100644 --- a/packages/CompanionDeviceManager/res/values-sv/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Appar"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Streama telefonens appar"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Låt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ge <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjärråtkomst till åt appar som är installerade på den här telefonen när den är ansluten."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Låt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ge <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjärråtkomst till appar som är installerade på den här surfplattan när den är ansluten."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Låt <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ge <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> fjärråtkomst till appar som är installerade på den här enheten när den är ansluten."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Den här tjänsten används för att streama appar mellan dina enheter"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Ge <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> åtkomstbehörighet till denna information på telefonen"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Aviseringar"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kan läsa alla aviseringar, inklusive information som kontakter, meddelanden och foton"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Foton och media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjänster"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Den här tjänsten delar foton, media och aviseringar från telefonen till andra enheter"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Den här tjänsten delar foton, media och aviseringar från telefonen till andra enheter"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Tillåt"</string> <string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Överför appbehörigheter till klockan"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Appar som installeras på klockan under konfigureringen får samma behörigheter som de har på telefonen så att konfigureringen ska bli enklare.\n\n Behörigheterna kan omfatta åtkomst till klockans mikrofon och plats."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml index 2533a97550ea..5ecbef055626 100644 --- a/packages/CompanionDeviceManager/res/values-sw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Programu"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Tiririsha programu za simu yako"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iipe <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ufikiaji wa mbali wa programu zilizosakinishwa kwenye simu hii wakati imeunganishwa."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iipe <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ufikiaji wa mbali wa programu zilizosakinishwa kwenye kompyuta hii kibao wakati imeunganishwa."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> iipe <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ufikiaji wa mbali wa programu zilizosakinishwa kwenye kifaa hiki wakati kimeunganishwa."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Huduma hii inatumika kutiririsha programu kati ya vifaa vyako"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Ruhusu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifikie maelezo haya kutoka kwenye simu yako"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Arifa"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Inaweza kusoma arifa zote, ikiwa ni pamoja na maelezo kama vile mikataba, ujumbe na picha"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Picha na maudhui"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Huduma za Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Huduma hii inashiriki picha, maudhui na arifa kutoka kwenye simu yako kwenda kwenye vifaa vingine"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Huduma hii inashiriki picha, maudhui na arifa kutoka kwenye simu yako kwenda kwenye vifaa vingine"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Ruhusu"</string> <string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string> - <string name="consent_ok" msgid="3662376764371001106">"Sawa"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Hamishia idhini za programu kwenye saa yako"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Ili kurahisisha kuweka mipangilio ya saa yako, programu ambazo zimesakinishwa kwenye saa yako wakati wa kuweka mipangilio zitatumia ruhusa sawa na zinazotumika kwenye simu yako.\n\n Ruhusa hizi huenda zikajumuisha ufikiaji wa maikrofoni ya saa yako na maelezo ya mahali ilipo saa yako."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml index 3f55444fa5c9..fd816749be0a 100644 --- a/packages/CompanionDeviceManager/res/values-ta/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"ஆப்ஸ்"</string> <string name="permission_apps_summary" msgid="798718816711515431">"உங்கள் மொபைலின் ஆப்ஸை ஸ்ட்ரீம் செய்யலாம்"</string> <string name="title_app_streaming" msgid="2270331024626446950">"மொபைலில் உள்ள இந்தத் தகவல்களை அணுக, <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கவும்"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"இணைக்கப்பட்டிருக்கும்போது இந்த மொபைலில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்திற்கு வழங்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கும்."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"இணைக்கப்பட்டிருக்கும்போது இந்த டேப்லெட்டில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்திற்கு வழங்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கும்."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"இணைக்கப்பட்டிருக்கும்போது இந்தச் சாதனத்தில் நிறுவப்பட்டிருக்கும் ஆப்ஸை அணுகுவதற்கான தொலைநிலை அணுகலை <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> சாதனத்திற்கு வழங்க <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதிக்கும்."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"சாதனங்களுக்கு இடையேயான சேவைகள்"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸை ஸ்ட்ரீம் செய்ய இந்தச் சேவை பயன்படுத்தப்படுகிறது"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"உங்கள் மொபைலிலிருந்து இந்தத் தகவலை அணுக <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ஆப்ஸை அனுமதியுங்கள்"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"அறிவிப்புகள்"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"ஒப்பந்தங்கள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்க முடியும்"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"தொடர்புகள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்க முடியும்"</string> <string name="permission_storage" msgid="6831099350839392343">"படங்கள் மற்றும் மீடியா"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play சேவைகள்"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை உங்கள் மொபைலில் இருந்து பிற சாதனங்களுக்கு இந்தச் சேவை பகிர்கிறது"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை உங்கள் மொபைலில் இருந்து பிற சாதனங்களுக்கு இந்தச் சேவை பகிர்கிறது"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"அனுமதி"</string> <string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string> - <string name="consent_ok" msgid="3662376764371001106">"சரி"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"ஆப்ஸ் அனுமதிகளை உங்கள் வாட்ச்சிற்கு மாற்றுதல்"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"உங்கள் வாட்ச் அமைவை எளிதாக்க, உங்கள் மொபைலில் வழங்கியுள்ள அனுமதிகளையே அமைவின்போது வாட்ச்சில் நிறுவப்பட்ட ஆப்ஸும் பயன்படுத்தும்.\n\n உங்கள் வாட்ச்சிலுள்ள மைக்ரோஃபோன், இருப்பிடம் ஆகியவற்றுக்கான அணுகலும் இந்த அனுமதிகளில் அடங்கக்கூடும்."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml index 552834e4ea25..30d3ed7f7b89 100644 --- a/packages/CompanionDeviceManager/res/values-te/strings.xml +++ b/packages/CompanionDeviceManager/res/values-te/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"యాప్లు"</string> <string name="permission_apps_summary" msgid="798718816711515431">"మీ ఫోన్ యాప్లను స్ట్రీమ్ చేయండి"</string> <string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యాప్ను అనుమతించండి"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"కనెక్ట్ అయినప్పుడు ఈ ఫోన్లో ఇన్స్టాల్ చేయబడిన యాప్లను యాక్సెస్ చేయడానికి <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> రిమోట్ యాక్సెస్ను అందించడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"కనెక్ట్ అయినప్పుడు ఈ టాబ్లెట్లో ఇన్స్టాల్ చేయబడిన యాప్లను యాక్సెస్ చేయడానికి <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> రిమోట్ యాక్సెస్ను అందించడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"కనెక్ట్ అయినప్పుడు ఈ పరికరంలో ఇన్స్టాల్ చేయబడిన యాప్లను యాక్సెస్ చేయడానికి <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> రిమోట్ యాక్సెస్ను అందించడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించండి."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"క్రాస్-డివైజ్ సర్వీసులు"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"మీ పరికరాల మధ్య యాప్లను స్ట్రీమ్ చేయడానికి ఈ సర్వీస్ ఉపయోగించబడుతుంది"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యాప్ను అనుమతించండి"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"నోటిఫికేషన్లు"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"ఒప్పందాలు, మెసేజ్లు, ఫోటోల వంటి సమాచారంతో సహా అన్ని నోటిఫికేషన్లను చదవగలరు"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"ఫోటోలు, మీడియా"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play సర్వీసులు"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"ఈ సర్వీస్ మీ ఫోన్ నుండి ఇతర పరికరాలకు ఫోటోలు, మీడియా, ఇంకా నోటిఫికేషన్లను షేర్ చేస్తుంది"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"ఈ సర్వీస్ మీ ఫోన్ నుండి ఇతర పరికరాలకు ఫోటోలు, మీడియా, ఇంకా నోటిఫికేషన్లను షేర్ చేస్తుంది"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"అనుమతించు"</string> <string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string> - <string name="consent_ok" msgid="3662376764371001106">"సరే"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"మీ వాచ్కు యాప్ అనుమతులను బదిలీ చేయండి"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"మీ వాచ్ను సెటప్ చేయడాన్ని సులభతరం చేయడానికి, సెటప్ సమయంలో మీ వాచ్లో ఇన్స్టాల్ చేయబడిన యాప్లు మీ ఫోన్లో యాప్లకు ఉన్న అవే అనుమతులను ఉపయోగిస్తాయి.\n\n ఈ అనుమతులతో మీ వాచ్ మైక్రోఫోన్, అలాగే లొకేషన్ కూడా ఉండవచ్చు."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml index c15ce034aceb..7fec8857c9f0 100644 --- a/packages/CompanionDeviceManager/res/values-th/strings.xml +++ b/packages/CompanionDeviceManager/res/values-th/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"แอป"</string> <string name="permission_apps_summary" msgid="798718816711515431">"สตรีมแอปของโทรศัพท์คุณ"</string> <string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในโทรศัพท์เครื่องนี้จากระยะไกลให้แก่ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> เมื่อมีการเชื่อมต่อ"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในแท็บเล็ตเครื่องนี้จากระยะไกลให้แก่ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> เมื่อมีการเชื่อมต่อ"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> มอบสิทธิ์เข้าถึงแอปพลิเคชันที่ติดตั้งในอุปกรณ์เครื่องนี้จากระยะไกลให้แก่ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> เมื่อมีการเชื่อมต่อ"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"บริการนี้ใช้เพื่อสตรีมแอประหว่างอุปกรณ์"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"อนุญาตให้ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"การแจ้งเตือน"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"สามารถอ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่าง รายชื่อผู้ติดต่อ ข้อความ และรูปภาพ"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"สามารถอ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่างรายชื่อติดต่อ ข้อความ และรูปภาพ"</string> <string name="permission_storage" msgid="6831099350839392343">"รูปภาพและสื่อ"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"บริการ Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"บริการนี้แชร์รูปภาพ สื่อ และการแจ้งเตือนจากโทรศัพท์กับอุปกรณ์อื่นๆ"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"บริการนี้แชร์รูปภาพ สื่อ และการแจ้งเตือนจากโทรศัพท์กับอุปกรณ์อื่นๆ"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"อนุญาต"</string> <string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string> - <string name="consent_ok" msgid="3662376764371001106">"ตกลง"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"โอนสิทธิ์ของแอปไปยังนาฬิกา"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"แอปที่ติดตั้งในนาฬิการะหว่างการตั้งค่าจะใช้สิทธิ์เดียวกันกับโทรศัพท์เพื่อให้การตั้งค่านาฬิกาง่ายขึ้น\n\n สิทธิ์เหล่านี้อาจรวมการเข้าถึงไมโครโฟนและตำแหน่งของนาฬิกา"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml index ee5ec161c195..cc68c4b5b348 100644 --- a/packages/CompanionDeviceManager/res/values-tl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Mga App"</string> <string name="permission_apps_summary" msgid="798718816711515431">"I-stream ang mga app ng iyong telepono"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang impormasyong ito sa iyong telepono"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na bigyan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ng malayuang access para ma-access ang mga application na naka-install sa teleponong ito kapag nakakonekta."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na bigyan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ng malayuang access para ma-access ang mga application na naka-install sa tablet na ito kapag nakakonekta."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na bigyan ang <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ng malayuang access para ma-access ang mga application na naka-install sa device na ito kapag nakakonekta."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Ginagamit ang serbisyong ito para mag-stream ng mga app sa pagitan ng iyong mga device"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Payagan ang <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na i-access ang impormasyon sa iyong telepono"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Mga Notification"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Mababasa ang lahat ng notification, kasama ang impormasyon gaya ng mga kontrata, mensahe, at larawan"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Mga larawan at media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Mga serbisyo ng Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Nagbabahagi ang serbisyong ito ng mga larawan, media, at notification mula sa iyong telepono patungo sa iba pang device"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Nagbabahagi ang serbisyong ito ng mga larawan, media, at notification mula sa iyong telepono patungo sa iba pang device"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"device"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Payagan"</string> <string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilipat sa iyong relo ang mga pahintulot sa app"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Para gawing mas madali na i-set up ang iyong relo, gagamitin ng mga app na naka-install sa relo mo sa oras ng pag-set up ang mga pahintulot na ginagamit din sa iyong telepono.\n\n Posibleng kasama sa mga pahintulot na ito ang access sa mikropono at lokasyon ng iyong relo."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index 07a5c2a29fbd..79a50ec10cb5 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Uygulamalar"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun uygulamalarını akışla aktarın"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, internete bağlanan bu telefondaki yüklü uygulamalara erişebilmesi için <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> adlı cihaza uzaktan erişim izni verin."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, internete bağlanan bu tabletteki yüklü uygulamalara erişebilmesi için <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> adlı cihaza uzaktan erişim izni verin."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, internete bağlanan bu cihazdaki yüklü uygulamalara erişebilmesi için <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> adlı cihaza uzaktan erişim izni verin."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Bu hizmet, cihazlarınız arasında uygulama aktarmak için kullanılır"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Bildirimler"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Kişiler, mesajlar ve fotoğraflar da dahil olmak üzere tüm bildirimleri okuyabilir"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Fotoğraflar ve medya"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play hizmetleri"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Bu hizmet, telefonunuzdaki fotoğraf, medya ve bildirimleri diğer cihazlarla paylaşır"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Bu hizmet, telefonunuzdaki fotoğraf, medya ve bildirimleri diğer cihazlarla paylaşır"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"İzin ver"</string> <string name="consent_no" msgid="2640796915611404382">"İzin verme"</string> - <string name="consent_ok" msgid="3662376764371001106">"Tamam"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Uygulama izinlerini saatinize aktarma"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Kurulum sırasında saatinize yüklenen uygulamalar, saat kurulumunuzu kolaylaştırmak için telefonunuzla aynı izinleri kullanır.\n\n Saatinizin mikrofonuna ve konumuna erişim bu izinlere dahil olabilir."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml index 8ab5bf1c6322..891cf603c285 100644 --- a/packages/CompanionDeviceManager/res/values-uk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Додатки"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Транслювати додатки телефона"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Надайте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до цієї інформації з телефона"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Дозвольте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> за наявності з’єднання надавати пристрою <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> віддалений доступ до додатків, установлених на цьому телефоні."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Дозвольте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> за наявності з’єднання надавати пристрою <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> віддалений доступ до додатків, установлених на цьому планшеті."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Дозвольте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> за наявності з’єднання надавати пристрою <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> віддалений доступ до додатків, установлених на цьому пристрої."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервіси для кількох пристроїв"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Цей сервіс використовується для трансляції додатків між вашими пристроями"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Надайте додатку <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> доступ до цієї інформації з телефона"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Сповіщення"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Може читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення та фотографії"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Фотографії та медіафайли"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Сервіси Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Цей сервіс передає фотографії, медіафайли та сповіщення з вашого телефона на інші пристрої"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Цей сервіс передає фотографії, медіафайли та сповіщення з вашого телефона на інші пристрої"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Дозволити"</string> <string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Перенести дозволи для додатків на годинник"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Задля зручності додатки, установлені на годиннику протягом налаштування, використовуватимуть ті самі дозволи, що й на телефоні.\n\n До таких дозволів може належати доступ до мікрофона й геоданих годинника."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml index 0c3686567826..a6f2d7b745cf 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"ایپس"</string> <string name="permission_apps_summary" msgid="798718816711515431">"اپنے فون کی ایپس کی سلسلہ بندی کریں"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اپنے فون سے ان معلومات تک رسائی حاصل کرنے کی اجازت دیں"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"منسلک ہونے پر، اس فون پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"منسلک ہونے پر، اس ٹیبلیٹ پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"منسلک ہونے پر، اس آلے پر انسٹال کردہ ایپلیکیشنز تک رسائی حاصل کرنے کے لیے <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کے لیے ریموٹ تک رسائی فراہم کرنے کی اجازت دیں۔"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس آلے کی سروس"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"یہ سروس آپ کے آلات کے درمیان ایپس کو اسٹریم کرنے کے لیے استعمال ہوتی ہے"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"اپنے فون سے اس معلومات تک رسائی حاصل Allow <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کرنے کی اجازت دیں"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"اطلاعات"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"معاہدوں، پیغامات اور تصاویر جیسی معلومات سمیت تمام اطلاعات پڑھ سکتے ہیں"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"تصاویر اور میڈیا"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play سروسز"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"یہ سروس آپ کے فون سے دیگر آلات پر تصاویر، میڈیا اور اطلاعات کا اشتراک کرتی ہے"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"یہ سروس آپ کے فون سے دیگر آلات پر تصاویر، میڈیا اور اطلاعات کا اشتراک کرتی ہے"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"اجازت دیں"</string> <string name="consent_no" msgid="2640796915611404382">"اجازت نہ دیں"</string> - <string name="consent_ok" msgid="3662376764371001106">"ٹھیک ہے"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"اپنی گھڑی پر ایپ کی اجازتیں منتقل کریں"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"آپ کی گھڑی کو سیٹ اپ کرنے کے عمل کو زیادہ آسان بنانے کے لیے، سیٹ اپ کے دوران آپ کی گھڑی پر انسٹال کردہ ایپس انہیں اجازتوں کا استعمال کریں گی جن کا استعمال آپ کا فون کرتا ہے۔\n\n ان اجازتوں میں آپ کی گھڑی کے مائیکروفون اور مقام تک کی رسائی شامل ہو سکتی ہے۔"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml index 59fc98f5a907..cc7ca6e094ca 100644 --- a/packages/CompanionDeviceManager/res/values-uz/strings.xml +++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Ilovalar"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Telefondagi ilovalarni translatsiya qilish"</string> <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ulanganda ushbu telefonda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ulanganda ushbu planshetda oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ulanganda ushbu qurilmada oʻrnatilgan ilovalarga masofadan kirish ruxsatini bering."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Bu xizmat ilovalarni qurilmalararo translatsiya qilishda ishlatiladi"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Bildirishnomalar"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqishi mumkin"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqishi mumkin"</string> <string name="permission_storage" msgid="6831099350839392343">"Suratlar va media"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xizmatlari"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Bu xizmat telefondagi rasm, media va bildirishnomalarni boshqa qurilmalarga ulashadi"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Bu xizmat telefondagi rasm, media va bildirishnomalarni boshqa qurilmalarga ulashadi"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Ruxsat"</string> <string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Ilova uchun ruxsatlarni soatingizga uzating"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Soatingizni sozlashni qulaylashtirish maqsadida sozlash paytida soatingizga oʻrnatilgan ilovalar telefoningiz bilan bir xil ruxsatlardan foydalanadi.\n\n Bunday ruxsatlarga soatingiz mikrofoni va joylashuv axborotiga ruxsatlar kirishi mumkin."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml index 8a96c4a7d1f2..9e62d8342782 100644 --- a/packages/CompanionDeviceManager/res/values-vi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"Ứng dụng"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Truyền các ứng dụng trên điện thoại của bạn"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào thông tin này trên điện thoại của bạn"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập từ xa vào các ứng dụng đã cài đặt trên <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> khi điện thoại này có kết nối."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập từ xa vào các ứng dụng đã cài đặt trên <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> khi máy tính bảng này có kết nối."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập từ xa vào các ứng dụng đã cài đặt trên <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> khi thiết bị này có kết nối."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Dịch vụ trên nhiều thiết bị"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Dịch vụ này được dùng để truyền ứng dụng giữa các thiết bị"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Cho phép <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> truy cập vào thông tin này trên điện thoại của bạn"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Thông báo"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Có thể đọc tất cả các thông báo, kể cả những thông tin như hợp đồng, tin nhắn và ảnh"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"Ảnh và nội dung nghe nhìn"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Dịch vụ Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Dịch vụ này chia sẻ ảnh, nội dung nghe nhìn và thông báo từ điện thoại của bạn sang các thiết bị khác"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Dịch vụ này chia sẻ ảnh, nội dung nghe nhìn và thông báo từ điện thoại của bạn sang các thiết bị khác"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Cho phép"</string> <string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string> - <string name="consent_ok" msgid="3662376764371001106">"OK"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Chuyển quyền cho ứng dụng sang đồng hồ"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Để thiết lập đồng hồ dễ dàng hơn, trong quá trình thiết lập, các ứng dụng được cài đặt trên đồng hồ của bạn sẽ sử dụng các quyền giống như trên điện thoại.\n\n Các quyền này có thể bao gồm quyền sử dụng micrô và thông tin vị trí của đồng hồ."</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml index 1ee43c91d53b..2c8d7b4c7d46 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"应用"</string> <string name="permission_apps_summary" msgid="798718816711515431">"流式传输手机的应用内容"</string> <string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”<strong></strong>访问您手机中的这项信息"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"在 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 连接到网络后,允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 远程访问该手机上安装的应用。"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"在 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 连接到网络后,允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 远程访问该平板电脑上安装的应用。"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"在 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> 连接到网络后,允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 远程访问该设备上安装的应用。"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"此服务用于在设备之间流式传输应用内容"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 访问您手机中的这项信息"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"通知"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"可以读取所有通知,包括合同、消息和照片等信息"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"照片和媒体内容"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服务"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"此服务可将您手机中的照片、媒体内容和通知分享给其他设备"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"此服务可将您手机中的照片、媒体内容和通知分享给其他设备"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"允许"</string> <string name="consent_no" msgid="2640796915611404382">"不允许"</string> - <string name="consent_ok" msgid="3662376764371001106">"确定"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"将应用权限转让给手表"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"为了让您更轻松地设置手表,在设置过程中安装在手表上的应用将使用与手机相同的权限。\n\n这些权限可能包括使用手表的麦克风和位置信息。"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml index fa2f0fc0961d..3219f20960e5 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string> <string name="permission_apps_summary" msgid="798718816711515431">"串流播放手機應用程式內容"</string> <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取您手機中的這項資料"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此手機上安裝的應用程式。"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此平板電腦上安裝的應用程式。"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"讓「<xliff:g id="APP_NAME">%1$s</xliff:g>」在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」連線時可透過遠端方式存取此裝置上安裝的應用程式。"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"此服務是用來在裝置間串流應用程式的內容"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取您手機中的這項資料"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"通知"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"此服務可將手機上的相片、媒體及通知分享到其他裝置"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"此服務可將手機上的相片、媒體及通知分享到其他裝置"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"允許"</string> <string name="consent_no" msgid="2640796915611404382">"不允許"</string> - <string name="consent_ok" msgid="3662376764371001106">"確定"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"將應用程式權限轉移至手錶"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"為簡化手錶的設定程序,在設定過程中安裝到手錶上的應用程式都將沿用手機上的權限。\n\n這些權限可能包括手錶麥克風和位置的存取權。"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml index abefde4c0288..83176d48d314 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml @@ -25,27 +25,27 @@ <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string> <string name="permission_apps_summary" msgid="798718816711515431">"串流傳輸手機應用程式內容"</string> <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取手機中的這項資訊"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>連上網際網路時可從遠端存取該手機上安裝的應用程式。"</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>連上網際網路時可從遠端存取該平板電腦上安裝的應用程式。"</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>在「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>連上網際網路時可從遠端存取該裝置上安裝的應用程式。"</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"這項服務是用來在裝置間串流傳輸應用程式的內容"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取你手機中的這項資訊"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"通知"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string> + <!-- no translation found for permission_notification_summary (884075314530071011) --> + <skip /> <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"這項服務可將手機上的相片、媒體及通知分享到其他裝置"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"這項服務可將手機上的相片、媒體及通知分享到其他裝置"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"允許"</string> <string name="consent_no" msgid="2640796915611404382">"不允許"</string> - <string name="consent_ok" msgid="3662376764371001106">"確定"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"將應用程式權限轉移到手錶上"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"為簡化手錶的設定程序,只要是在設定過程中安裝到手錶上的應用程式,都將沿用手機上的權限。\n\n 這些權限可能包括手錶的麥克風和位置資訊存取權。"</string> </resources> diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml index 1c7cad33c0a7..3f5031f87432 100644 --- a/packages/CompanionDeviceManager/res/values-zu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml @@ -25,27 +25,26 @@ <string name="permission_apps" msgid="6142133265286656158">"Ama-app"</string> <string name="permission_apps_summary" msgid="798718816711515431">"Sakaza ama-app wefoni yakho"</string> <string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ifinyelele lolu lwazi kusukela efonini yakho"</string> - <string name="summary_app_streaming" product="default" msgid="6105916810614498138">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukunikezela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ngokufinyelela kwerimothi kuma-applications afakiwe kule foni uma ixhunyiwe."</string> - <string name="summary_app_streaming" product="tablet" msgid="2996373715966272792">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukunikezela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ngokufinyelela kwerimothi kuma-applications afakiwe kule thebhulethi uma ixhunyiwe."</string> - <string name="summary_app_streaming" product="device" msgid="7614171699434639963">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukunikezela <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ngokufinyelela kwerimothi kuma-applications afakiwe kule divayisi uma ixhunyiwe."</string> <string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string> - <string name="helper_summary_app_streaming" msgid="5344341720432827388">"Le sevisi isetshenziselwa ukusakaza-bukhoma ama-app phakathi kwamadivayisi akho"</string> + <!-- no translation found for helper_summary_app_streaming (7380294597268573523) --> + <skip /> <string name="title_automotive_projection" msgid="3296005598978412847"></string> <string name="summary_automotive_projection" msgid="8683801274662496164"></string> <string name="title_computer" msgid="4693714143506569253">"Vumela <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ukufinyelela lolu lwazi kusuka efonini yakho"</string> <string name="summary_computer" msgid="3798467601598297062"></string> <string name="permission_notification" msgid="693762568127741203">"Izaziso"</string> - <string name="permission_notification_summary" msgid="4398672775023193663">"Ingafunda zonke izaziso, okufaka phakathi ulwazi olufana nomakhontilaki, imiyalezo, nezithombe"</string> + <string name="permission_notification_summary" msgid="884075314530071011">"Ingafunda zonke izaziso, okubandakanya ulwazi olufana noxhumana nabo, imilayezo, nezithombe"</string> <string name="permission_storage" msgid="6831099350839392343">"Izithombe nemidiya"</string> <string name="permission_storage_summary" msgid="3918240895519506417"></string> <string name="helper_title_computer" msgid="4671071173916176037">"Amasevisi we-Google Play"</string> - <string name="helper_summary_computer" product="default" msgid="467996390095403648">"Le sevisi yabelana ngezithombe, imidiya, nezaziso kusukela kufoni yakho ukuya kwamanye amadivaysi"</string> - <string name="helper_summary_computer" product="tablet" msgid="467996390095403648">"Le sevisi yabelana ngezithombe, imidiya, nezaziso kusukela kufoni yakho ukuya kwamanye amadivaysi"</string> + <!-- no translation found for helper_summary_computer (1676407599909474428) --> + <skip /> <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string> <string name="summary_generic" msgid="2346762210105903720"></string> <string name="consent_yes" msgid="8344487259618762872">"Vumela"</string> <string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string> - <string name="consent_ok" msgid="3662376764371001106">"KULUNGILE"</string> + <!-- no translation found for consent_back (2560683030046918882) --> + <skip /> <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Dlulisela izimvume ze-app ewashini lakho"</string> <string name="permission_sync_summary" msgid="8873391306499120778">"Ukuze wenze kube lula ukusetha iwashi lakho, ama-app afakwe ewashini lakho phakathi nokusetha azosebenzisa izimvume ezifanayo nezefoni yakho.\n\n Lezi zimvume zingabandakanya ukufinyelela kumakrofoni nendawo yewashi lakho."</string> </resources> diff --git a/packages/ConnectivityT/OWNERS b/packages/ConnectivityT/OWNERS deleted file mode 100644 index adbcd4b5a36b..000000000000 --- a/packages/ConnectivityT/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# OWNERS block for code move: b/222234190 -reminv@google.com - -# file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking -# per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp deleted file mode 100644 index bc278528570f..000000000000 --- a/packages/ConnectivityT/framework-t/Android.bp +++ /dev/null @@ -1,205 +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 { - // See: http://go/android-license-faq - default_applicable_licenses: ["Android-Apache-2.0"], -} - -// NetworkStats related libraries. - -filegroup { - name: "framework-connectivity-netstats-internal-sources", - srcs: [ - "src/android/app/usage/*.java", - "src/android/net/DataUsageRequest.*", - "src/android/net/INetworkStatsService.aidl", - "src/android/net/INetworkStatsSession.aidl", - "src/android/net/NetworkIdentity.java", - "src/android/net/NetworkIdentitySet.java", - "src/android/net/NetworkStateSnapshot.*", - "src/android/net/NetworkStats.*", - "src/android/net/NetworkStatsAccess.*", - "src/android/net/NetworkStatsCollection.*", - "src/android/net/NetworkStatsHistory.*", - "src/android/net/NetworkTemplate.*", - "src/android/net/TrafficStats.java", - "src/android/net/UnderlyingNetworkInfo.*", - "src/android/net/netstats/**/*.*", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-netstats-aidl-export-sources", - srcs: [ - "aidl-export/android/net/NetworkStats.aidl", - "aidl-export/android/net/NetworkTemplate.aidl", - ], - path: "aidl-export", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-netstats-sources", - srcs: [ - ":framework-connectivity-netstats-internal-sources", - ":framework-connectivity-netstats-aidl-export-sources", - ], - visibility: [ - "//visibility:private", - ], -} - -// Nsd related libraries. - -filegroup { - name: "framework-connectivity-nsd-internal-sources", - srcs: [ - "src/android/net/nsd/*.aidl", - "src/android/net/nsd/*.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-nsd-aidl-export-sources", - srcs: [ - "aidl-export/android/net/nsd/*.aidl", - ], - path: "aidl-export", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-nsd-sources", - srcs: [ - ":framework-connectivity-nsd-internal-sources", - ":framework-connectivity-nsd-aidl-export-sources", - ], - visibility: [ - "//visibility:private", - ], -} - -// IpSec related libraries. - -filegroup { - name: "framework-connectivity-ipsec-sources", - srcs: [ - "src/android/net/IIpSecService.aidl", - "src/android/net/IpSec*.*", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// Ethernet related libraries. - -filegroup { - name: "framework-connectivity-ethernet-sources", - srcs: [ - "src/android/net/EthernetManager.java", - "src/android/net/EthernetNetworkManagementException.java", - "src/android/net/EthernetNetworkManagementException.aidl", - "src/android/net/EthernetNetworkSpecifier.java", - "src/android/net/EthernetNetworkUpdateRequest.java", - "src/android/net/EthernetNetworkUpdateRequest.aidl", - "src/android/net/IEthernetManager.aidl", - "src/android/net/IEthernetServiceListener.aidl", - "src/android/net/INetworkInterfaceOutcomeReceiver.aidl", - "src/android/net/ITetheredInterfaceCallback.aidl", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// Connectivity-T common libraries. - -filegroup { - name: "framework-connectivity-tiramisu-internal-sources", - srcs: [ - "src/android/net/ConnectivityFrameworkInitializerTiramisu.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// TODO: remove this empty filegroup. -filegroup { - name: "framework-connectivity-tiramisu-sources", - srcs: [], - visibility: ["//frameworks/base"], -} - -filegroup { - name: "framework-connectivity-tiramisu-updatable-sources", - srcs: [ - ":framework-connectivity-ethernet-sources", - ":framework-connectivity-ipsec-sources", - ":framework-connectivity-netstats-sources", - ":framework-connectivity-nsd-sources", - ":framework-connectivity-tiramisu-internal-sources", - ], - visibility: [ - "//frameworks/base", - "//packages/modules/Connectivity:__subpackages__", - ], -} - -cc_library_shared { - name: "libframework-connectivity-tiramisu-jni", - min_sdk_version: "30", - cflags: [ - "-Wall", - "-Werror", - "-Wno-unused-parameter", - // Don't warn about S API usage even with - // min_sdk 30: the library is only loaded - // on S+ devices - "-Wno-unguarded-availability", - "-Wthread-safety", - ], - srcs: [ - "jni/android_net_TrafficStats.cpp", - "jni/onload.cpp", - ], - shared_libs: [ - "libandroid", - "liblog", - "libnativehelper", - ], - stl: "none", - apex_available: [ - "com.android.tethering", - ], -} diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl deleted file mode 100644 index d06ca65a3e0d..000000000000 --- a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2011, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -parcelable NetworkStats; diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl deleted file mode 100644 index 3d37488d9881..000000000000 --- a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2011, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -parcelable NetworkTemplate; diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl deleted file mode 100644 index 657bdd1e8706..000000000000 --- a/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl +++ /dev/null @@ -1,19 +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.net.nsd; - -@JavaOnlyStableParcelable parcelable NsdServiceInfo;
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp b/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp deleted file mode 100644 index f3c58b112f0d..000000000000 --- a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <android/file_descriptor_jni.h> -#include <android/multinetwork.h> -#include <nativehelper/JNIHelp.h> - -namespace android { - -static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, jint tag, jint uid) { - int fd = AFileDescriptor_getFd(env, fileDescriptor); - if (fd == -1) return -EBADF; - return android_tag_socket_with_uid(fd, tag, uid); -} - -static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) { - int fd = AFileDescriptor_getFd(env, fileDescriptor); - if (fd == -1) return -EBADF; - return android_untag_socket(fd); -} - -static const JNINativeMethod gMethods[] = { - /* name, signature, funcPtr */ - { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*) tagSocketFd }, - { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*) untagSocketFd }, -}; - -int register_android_net_TrafficStats(JNIEnv* env) { - return jniRegisterNativeMethods(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); -} - -}; // namespace android - diff --git a/packages/ConnectivityT/framework-t/jni/onload.cpp b/packages/ConnectivityT/framework-t/jni/onload.cpp deleted file mode 100644 index 1fb42c63477e..000000000000 --- a/packages/ConnectivityT/framework-t/jni/onload.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "FrameworkConnectivityJNI" - -#include <log/log.h> -#include <nativehelper/JNIHelp.h> - -namespace android { - -int register_android_net_TrafficStats(JNIEnv* env); - -extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { - JNIEnv *env; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); - return JNI_ERR; - } - - if (register_android_net_TrafficStats(env) < 0) return JNI_ERR; - - return JNI_VERSION_1_6; -} - -}; // namespace android - diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java deleted file mode 100644 index 74fe4bd46cde..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java +++ /dev/null @@ -1,744 +0,0 @@ -/** - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package android.app.usage; - -import android.annotation.IntDef; -import android.annotation.Nullable; -import android.content.Context; -import android.net.INetworkStatsService; -import android.net.INetworkStatsSession; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.TrafficStats; -import android.os.RemoteException; -import android.util.Log; - -import com.android.net.module.util.CollectionUtils; - -import dalvik.system.CloseGuard; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; - -/** - * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects - * are returned as results to various queries in {@link NetworkStatsManager}. - */ -public final class NetworkStats implements AutoCloseable { - private final static String TAG = "NetworkStats"; - - private final CloseGuard mCloseGuard = CloseGuard.get(); - - /** - * Start timestamp of stats collected - */ - private final long mStartTimeStamp; - - /** - * End timestamp of stats collected - */ - private final long mEndTimeStamp; - - /** - * Non-null array indicates the query enumerates over uids. - */ - private int[] mUids; - - /** - * Index of the current uid in mUids when doing uid enumeration or a single uid value, - * depending on query type. - */ - private int mUidOrUidIndex; - - /** - * Tag id in case if was specified in the query. - */ - private int mTag = android.net.NetworkStats.TAG_NONE; - - /** - * State in case it was not specified in the query. - */ - private int mState = Bucket.STATE_ALL; - - /** - * The session while the query requires it, null if all the stats have been collected or close() - * has been called. - */ - private INetworkStatsSession mSession; - private NetworkTemplate mTemplate; - - /** - * Results of a summary query. - */ - private android.net.NetworkStats mSummary = null; - - /** - * Results of detail queries. - */ - private NetworkStatsHistory mHistory = null; - - /** - * Where we are in enumerating over the current result. - */ - private int mEnumerationIndex = 0; - - /** - * Recycling entry objects to prevent heap fragmentation. - */ - private android.net.NetworkStats.Entry mRecycledSummaryEntry = null; - private NetworkStatsHistory.Entry mRecycledHistoryEntry = null; - - /** @hide */ - NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp, - long endTimestamp, INetworkStatsService statsService) - throws RemoteException, SecurityException { - // Open network stats session - mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName()); - mCloseGuard.open("close"); - mTemplate = template; - mStartTimeStamp = startTimestamp; - mEndTimeStamp = endTimestamp; - } - - @Override - protected void finalize() throws Throwable { - try { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } finally { - super.finalize(); - } - } - - // -------------------------BEGINNING OF PUBLIC API----------------------------------- - - /** - * Buckets are the smallest elements of a query result. As some dimensions of a result may be - * aggregated (e.g. time or state) some values may be equal across all buckets. - */ - public static class Bucket { - /** @hide */ - @IntDef(prefix = { "STATE_" }, value = { - STATE_ALL, - STATE_DEFAULT, - STATE_FOREGROUND - }) - @Retention(RetentionPolicy.SOURCE) - public @interface State {} - - /** - * Combined usage across all states. - */ - public static final int STATE_ALL = -1; - - /** - * Usage not accounted for in any other state. - */ - public static final int STATE_DEFAULT = 0x1; - - /** - * Foreground usage. - */ - public static final int STATE_FOREGROUND = 0x2; - - /** - * Special UID value for aggregate/unspecified. - */ - public static final int UID_ALL = android.net.NetworkStats.UID_ALL; - - /** - * Special UID value for removed apps. - */ - public static final int UID_REMOVED = TrafficStats.UID_REMOVED; - - /** - * Special UID value for data usage by tethering. - */ - public static final int UID_TETHERING = TrafficStats.UID_TETHERING; - - /** @hide */ - @IntDef(prefix = { "METERED_" }, value = { - METERED_ALL, - METERED_NO, - METERED_YES - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Metered {} - - /** - * Combined usage across all metered states. Covers metered and unmetered usage. - */ - public static final int METERED_ALL = -1; - - /** - * Usage that occurs on an unmetered network. - */ - public static final int METERED_NO = 0x1; - - /** - * Usage that occurs on a metered network. - * - * <p>A network is classified as metered when the user is sensitive to heavy data usage on - * that connection. - */ - public static final int METERED_YES = 0x2; - - /** @hide */ - @IntDef(prefix = { "ROAMING_" }, value = { - ROAMING_ALL, - ROAMING_NO, - ROAMING_YES - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Roaming {} - - /** - * Combined usage across all roaming states. Covers both roaming and non-roaming usage. - */ - public static final int ROAMING_ALL = -1; - - /** - * Usage that occurs on a home, non-roaming network. - * - * <p>Any cellular usage in this bucket was incurred while the device was connected to a - * tower owned or operated by the user's wireless carrier, or a tower that the user's - * wireless carrier has indicated should be treated as a home network regardless. - * - * <p>This is also the default value for network types that do not support roaming. - */ - public static final int ROAMING_NO = 0x1; - - /** - * Usage that occurs on a roaming network. - * - * <p>Any cellular usage in this bucket as incurred while the device was roaming on another - * carrier's network, for which additional charges may apply. - */ - public static final int ROAMING_YES = 0x2; - - /** @hide */ - @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { - DEFAULT_NETWORK_ALL, - DEFAULT_NETWORK_NO, - DEFAULT_NETWORK_YES - }) - @Retention(RetentionPolicy.SOURCE) - public @interface DefaultNetworkStatus {} - - /** - * Combined usage for this network regardless of default network status. - */ - public static final int DEFAULT_NETWORK_ALL = -1; - - /** - * Usage that occurs while this network is not a default network. - * - * <p>This implies that the app responsible for this usage requested that it occur on a - * specific network different from the one(s) the system would have selected for it. - */ - public static final int DEFAULT_NETWORK_NO = 0x1; - - /** - * Usage that occurs while this network is a default network. - * - * <p>This implies that the app either did not select a specific network for this usage, - * or it selected a network that the system could have selected for app traffic. - */ - public static final int DEFAULT_NETWORK_YES = 0x2; - - /** - * Special TAG value for total data across all tags - */ - public static final int TAG_NONE = android.net.NetworkStats.TAG_NONE; - - private int mUid; - private int mTag; - private int mState; - private int mDefaultNetworkStatus; - private int mMetered; - private int mRoaming; - private long mBeginTimeStamp; - private long mEndTimeStamp; - private long mRxBytes; - private long mRxPackets; - private long mTxBytes; - private long mTxPackets; - - private static int convertSet(@State int state) { - switch (state) { - case STATE_ALL: return android.net.NetworkStats.SET_ALL; - case STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT; - case STATE_FOREGROUND: return android.net.NetworkStats.SET_FOREGROUND; - } - return 0; - } - - private static @State int convertState(int networkStatsSet) { - switch (networkStatsSet) { - case android.net.NetworkStats.SET_ALL : return STATE_ALL; - case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT; - case android.net.NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; - } - return 0; - } - - private static int convertUid(int uid) { - switch (uid) { - case TrafficStats.UID_REMOVED: return UID_REMOVED; - case TrafficStats.UID_TETHERING: return UID_TETHERING; - } - return uid; - } - - private static int convertTag(int tag) { - switch (tag) { - case android.net.NetworkStats.TAG_NONE: return TAG_NONE; - } - return tag; - } - - private static @Metered int convertMetered(int metered) { - switch (metered) { - case android.net.NetworkStats.METERED_ALL : return METERED_ALL; - case android.net.NetworkStats.METERED_NO: return METERED_NO; - case android.net.NetworkStats.METERED_YES: return METERED_YES; - } - return 0; - } - - private static @Roaming int convertRoaming(int roaming) { - switch (roaming) { - case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; - case android.net.NetworkStats.ROAMING_NO: return ROAMING_NO; - case android.net.NetworkStats.ROAMING_YES: return ROAMING_YES; - } - return 0; - } - - private static @DefaultNetworkStatus int convertDefaultNetworkStatus( - int defaultNetworkStatus) { - switch (defaultNetworkStatus) { - case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL; - case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO; - case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES; - } - return 0; - } - - public Bucket() { - } - - /** - * Key of the bucket. Usually an app uid or one of the following special values:<p /> - * <ul> - * <li>{@link #UID_REMOVED}</li> - * <li>{@link #UID_TETHERING}</li> - * <li>{@link android.os.Process#SYSTEM_UID}</li> - * </ul> - * @return Bucket key. - */ - public int getUid() { - return mUid; - } - - /** - * Tag of the bucket.<p /> - * @return Bucket tag. - */ - public int getTag() { - return mTag; - } - - /** - * Usage state. One of the following values:<p/> - * <ul> - * <li>{@link #STATE_ALL}</li> - * <li>{@link #STATE_DEFAULT}</li> - * <li>{@link #STATE_FOREGROUND}</li> - * </ul> - * @return Usage state. - */ - public @State int getState() { - return mState; - } - - /** - * Metered state. One of the following values:<p/> - * <ul> - * <li>{@link #METERED_ALL}</li> - * <li>{@link #METERED_NO}</li> - * <li>{@link #METERED_YES}</li> - * </ul> - * <p>A network is classified as metered when the user is sensitive to heavy data usage on - * that connection. Apps may warn before using these networks for large downloads. The - * metered state can be set by the user within data usage network restrictions. - */ - public @Metered int getMetered() { - return mMetered; - } - - /** - * Roaming state. One of the following values:<p/> - * <ul> - * <li>{@link #ROAMING_ALL}</li> - * <li>{@link #ROAMING_NO}</li> - * <li>{@link #ROAMING_YES}</li> - * </ul> - */ - public @Roaming int getRoaming() { - return mRoaming; - } - - /** - * Default network status. One of the following values:<p/> - * <ul> - * <li>{@link #DEFAULT_NETWORK_ALL}</li> - * <li>{@link #DEFAULT_NETWORK_NO}</li> - * <li>{@link #DEFAULT_NETWORK_YES}</li> - * </ul> - */ - public @DefaultNetworkStatus int getDefaultNetworkStatus() { - return mDefaultNetworkStatus; - } - - /** - * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Start of interval. - */ - public long getStartTimeStamp() { - return mBeginTimeStamp; - } - - /** - * End timestamp of the bucket's time interval. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return End of interval. - */ - public long getEndTimeStamp() { - return mEndTimeStamp; - } - - /** - * Number of bytes received during the bucket's time interval. Statistics are measured at - * the network layer, so they include both TCP and UDP usage. - * @return Number of bytes. - */ - public long getRxBytes() { - return mRxBytes; - } - - /** - * Number of bytes transmitted during the bucket's time interval. Statistics are measured at - * the network layer, so they include both TCP and UDP usage. - * @return Number of bytes. - */ - public long getTxBytes() { - return mTxBytes; - } - - /** - * Number of packets received during the bucket's time interval. Statistics are measured at - * the network layer, so they include both TCP and UDP usage. - * @return Number of packets. - */ - public long getRxPackets() { - return mRxPackets; - } - - /** - * Number of packets transmitted during the bucket's time interval. Statistics are measured - * at the network layer, so they include both TCP and UDP usage. - * @return Number of packets. - */ - public long getTxPackets() { - return mTxPackets; - } - } - - /** - * Fills the recycled bucket with data of the next bin in the enumeration. - * @param bucketOut Bucket to be filled with data. If null, the method does - * nothing and returning false. - * @return true if successfully filled the bucket, false otherwise. - */ - public boolean getNextBucket(@Nullable Bucket bucketOut) { - if (mSummary != null) { - return getNextSummaryBucket(bucketOut); - } else { - return getNextHistoryBucket(bucketOut); - } - } - - /** - * Check if it is possible to ask for a next bucket in the enumeration. - * @return true if there is at least one more bucket. - */ - public boolean hasNextBucket() { - if (mSummary != null) { - return mEnumerationIndex < mSummary.size(); - } else if (mHistory != null) { - return mEnumerationIndex < mHistory.size() - || hasNextUid(); - } - return false; - } - - /** - * Closes the enumeration. Call this method before this object gets out of scope. - */ - @Override - public void close() { - if (mSession != null) { - try { - mSession.close(); - } catch (RemoteException e) { - Log.w(TAG, e); - // Otherwise, meh - } - } - mSession = null; - if (mCloseGuard != null) { - mCloseGuard.close(); - } - } - - // -------------------------END OF PUBLIC API----------------------------------- - - /** - * Collects device summary results into a Bucket. - * @throws RemoteException - */ - Bucket getDeviceSummaryForNetwork() throws RemoteException { - mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, mStartTimeStamp, mEndTimeStamp); - - // Setting enumeration index beyond end to avoid accidental enumeration over data that does - // not belong to the calling user. - mEnumerationIndex = mSummary.size(); - - return getSummaryAggregate(); - } - - /** - * Collects summary results and sets summary enumeration mode. - * @throws RemoteException - */ - void startSummaryEnumeration() throws RemoteException { - mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, - false /* includeTags */); - mEnumerationIndex = 0; - } - - /** - * Collects tagged summary results and sets summary enumeration mode. - * @throws RemoteException - */ - void startTaggedSummaryEnumeration() throws RemoteException { - mSummary = mSession.getTaggedSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp); - mEnumerationIndex = 0; - } - - /** - * Collects history results for uid and resets history enumeration index. - */ - void startHistoryUidEnumeration(int uid, int tag, int state) { - mHistory = null; - try { - mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, - Bucket.convertSet(state), tag, NetworkStatsHistory.FIELD_ALL, - mStartTimeStamp, mEndTimeStamp); - setSingleUidTagState(uid, tag, state); - } catch (RemoteException e) { - Log.w(TAG, e); - // Leaving mHistory null - } - mEnumerationIndex = 0; - } - - /** - * Collects history results for network and resets history enumeration index. - */ - void startHistoryDeviceEnumeration() { - try { - mHistory = mSession.getHistoryIntervalForNetwork( - mTemplate, NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - } catch (RemoteException e) { - Log.w(TAG, e); - mHistory = null; - } - mEnumerationIndex = 0; - } - - /** - * Starts uid enumeration for current user. - * @throws RemoteException - */ - void startUserUidEnumeration() throws RemoteException { - // TODO: getRelevantUids should be sensitive to time interval. When that's done, - // the filtering logic below can be removed. - int[] uids = mSession.getRelevantUids(); - // Filtering of uids with empty history. - final ArrayList<Integer> filteredUids = new ArrayList<>(); - for (int uid : uids) { - try { - NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid, - android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, - NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - if (history != null && history.size() > 0) { - filteredUids.add(uid); - } - } catch (RemoteException e) { - Log.w(TAG, "Error while getting history of uid " + uid, e); - } - } - mUids = CollectionUtils.toIntArray(filteredUids); - mUidOrUidIndex = -1; - stepHistory(); - } - - /** - * Steps to next uid in enumeration and collects history for that. - */ - private void stepHistory(){ - if (hasNextUid()) { - stepUid(); - mHistory = null; - try { - mHistory = mSession.getHistoryIntervalForUid(mTemplate, getUid(), - android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, - NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - } catch (RemoteException e) { - Log.w(TAG, e); - // Leaving mHistory null - } - mEnumerationIndex = 0; - } - } - - private void fillBucketFromSummaryEntry(Bucket bucketOut) { - bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); - bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); - bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - bucketOut.mDefaultNetworkStatus = Bucket.convertDefaultNetworkStatus( - mRecycledSummaryEntry.defaultNetwork); - bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); - bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); - bucketOut.mBeginTimeStamp = mStartTimeStamp; - bucketOut.mEndTimeStamp = mEndTimeStamp; - bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes; - bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets; - bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes; - bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets; - } - - /** - * Getting the next item in summary enumeration. - * @param bucketOut Next item will be set here. - * @return true if a next item could be set. - */ - private boolean getNextSummaryBucket(@Nullable Bucket bucketOut) { - if (bucketOut != null && mEnumerationIndex < mSummary.size()) { - mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry); - fillBucketFromSummaryEntry(bucketOut); - return true; - } - return false; - } - - Bucket getSummaryAggregate() { - if (mSummary == null) { - return null; - } - Bucket bucket = new Bucket(); - if (mRecycledSummaryEntry == null) { - mRecycledSummaryEntry = new android.net.NetworkStats.Entry(); - } - mSummary.getTotal(mRecycledSummaryEntry); - fillBucketFromSummaryEntry(bucket); - return bucket; - } - - /** - * Getting the next item in a history enumeration. - * @param bucketOut Next item will be set here. - * @return true if a next item could be set. - */ - private boolean getNextHistoryBucket(@Nullable Bucket bucketOut) { - if (bucketOut != null && mHistory != null) { - if (mEnumerationIndex < mHistory.size()) { - mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++, - mRecycledHistoryEntry); - bucketOut.mUid = Bucket.convertUid(getUid()); - bucketOut.mTag = Bucket.convertTag(mTag); - bucketOut.mState = mState; - bucketOut.mDefaultNetworkStatus = Bucket.DEFAULT_NETWORK_ALL; - bucketOut.mMetered = Bucket.METERED_ALL; - bucketOut.mRoaming = Bucket.ROAMING_ALL; - bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; - bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + - mRecycledHistoryEntry.bucketDuration; - bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes; - bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets; - bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes; - bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets; - return true; - } else if (hasNextUid()) { - stepHistory(); - return getNextHistoryBucket(bucketOut); - } - } - return false; - } - - // ------------------ UID LOGIC------------------------ - - private boolean isUidEnumeration() { - return mUids != null; - } - - private boolean hasNextUid() { - return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length; - } - - private int getUid() { - // Check if uid enumeration. - if (isUidEnumeration()) { - if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) { - throw new IndexOutOfBoundsException( - "Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length); - } - return mUids[mUidOrUidIndex]; - } - // Single uid mode. - return mUidOrUidIndex; - } - - private void setSingleUidTagState(int uid, int tag, int state) { - mUidOrUidIndex = uid; - mTag = tag; - mState = state; - } - - private void stepUid() { - if (mUids != null) { - ++mUidOrUidIndex; - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java deleted file mode 100644 index f41475bea190..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java +++ /dev/null @@ -1,1238 +0,0 @@ -/** - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package android.app.usage; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; - -import android.Manifest; -import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.annotation.WorkerThread; -import android.app.usage.NetworkStats.Bucket; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.DataUsageRequest; -import android.net.INetworkStatsService; -import android.net.Network; -import android.net.NetworkStack; -import android.net.NetworkStateSnapshot; -import android.net.NetworkTemplate; -import android.net.UnderlyingNetworkInfo; -import android.net.netstats.IUsageCallback; -import android.net.netstats.NetworkStatsDataMigrationUtils; -import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProvider; -import android.os.Build; -import android.os.Handler; -import android.os.RemoteException; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.NetworkIdentityUtils; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.Executor; - -/** - * Provides access to network usage history and statistics. Usage data is collected in - * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. - * <p /> - * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and - * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain - * data about themselves. See the below note for special cases in which apps can obtain data about - * other applications. - * <h3> - * Summary queries - * </h3> - * {@link #querySummaryForDevice} <p /> - * {@link #querySummaryForUser} <p /> - * {@link #querySummary} <p /> - * These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key, state, metered and roaming combination. In case of the user-wide - * and device-wide summaries a single bucket containing the totalised network usage is returned. - * <h3> - * History queries - * </h3> - * {@link #queryDetailsForUid} <p /> - * {@link #queryDetails} <p /> - * These queries do not aggregate over time but do aggregate over state, metered and roaming. - * Therefore there can be multiple buckets for a particular key. However, all Buckets will have - * {@code state} {@link NetworkStats.Bucket#STATE_ALL}, - * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * {@code metered } {@link NetworkStats.Bucket#METERED_ALL}, - * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}. - * <p /> - * <b>NOTE:</b> Calling {@link #querySummaryForDevice} or accessing stats for apps other than the - * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, - * which is a system-level permission and will not be granted to third-party apps. However, - * declaring the permission implies intention to use the API and the user of the device can grant - * permission through the Settings application. - * <p /> - * Profile owner apps are automatically granted permission to query data on the profile they manage - * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier- - * privileged apps likewise get access to usage data for all users on the device. - * <p /> - * In addition to tethering usage, usage by removed users and apps, and usage by the system - * is also included in the results for callers with one of these higher levels of access. - * <p /> - * <b>NOTE:</b> Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required - * the above permission, even to access an app's own data usage, and carrier-privileged apps were - * not included. - */ -@SystemService(Context.NETWORK_STATS_SERVICE) -public class NetworkStatsManager { - private static final String TAG = "NetworkStatsManager"; - private static final boolean DBG = false; - - /** @hide */ - public static final int CALLBACK_LIMIT_REACHED = 0; - /** @hide */ - public static final int CALLBACK_RELEASED = 1; - - /** - * Minimum data usage threshold for registering usage callbacks. - * - * Requests registered with a threshold lower than this will only be triggered once this minimum - * is reached. - * @hide - */ - public static final long MIN_THRESHOLD_BYTES = 2 * 1_048_576L; // 2MiB - - private final Context mContext; - private final INetworkStatsService mService; - - /** - * @deprecated Use {@link NetworkStatsDataMigrationUtils#PREFIX_XT} - * instead. - * @hide - */ - @Deprecated - public static final String PREFIX_DEV = "dev"; - - /** @hide */ - public static final int FLAG_POLL_ON_OPEN = 1 << 0; - /** @hide */ - public static final int FLAG_POLL_FORCE = 1 << 1; - /** @hide */ - public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2; - - /** - * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is - * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along - * with NR state as connected. This is a concept added by NetworkStats on top of the telephony - * constants for backward compatibility of metrics so this should not be overlapped with any of - * the {@code TelephonyManager.NETWORK_TYPE_*} constants. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int NETWORK_TYPE_5G_NSA = -2; - - private int mFlags; - - /** @hide */ - @VisibleForTesting - public NetworkStatsManager(Context context, INetworkStatsService service) { - mContext = context; - mService = service; - setPollOnOpen(true); - setAugmentWithSubscriptionPlan(true); - } - - /** @hide */ - public INetworkStatsService getBinder() { - return mService; - } - - /** - * Set poll on open flag to indicate the poll is needed before service gets statistics - * result. This is default enabled. However, for any non-privileged caller, the poll might - * be omitted in case of rate limiting. - * - * @param pollOnOpen true if poll is needed. - * @hide - */ - // The system will ignore any non-default values for non-privileged - // processes, so processes that don't hold the appropriate permissions - // can make no use of this API. - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void setPollOnOpen(boolean pollOnOpen) { - if (pollOnOpen) { - mFlags |= FLAG_POLL_ON_OPEN; - } else { - mFlags &= ~FLAG_POLL_ON_OPEN; - } - } - - /** - * Set poll force flag to indicate that calling any subsequent query method will force a stats - * poll. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @SystemApi(client = MODULE_LIBRARIES) - public void setPollForce(boolean pollForce) { - if (pollForce) { - mFlags |= FLAG_POLL_FORCE; - } else { - mFlags &= ~FLAG_POLL_FORCE; - } - } - - /** @hide */ - public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) { - if (augmentWithSubscriptionPlan) { - mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; - } else { - mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; - } - } - - /** - * Query network usage statistics summaries. - * - * Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and - * roaming. This means the bucket's start and end timestamp will be the same as the - * 'startTime' and 'endTime' arguments. State is going to be - * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, - * tag {@link NetworkStats.Bucket#TAG_NONE}, - * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, - * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @return Bucket Summarised data usage. - * - * @hide - */ - @NonNull - @WorkerThread - @SystemApi(client = MODULE_LIBRARIES) - public Bucket querySummaryForDevice(@NonNull NetworkTemplate template, - long startTime, long endTime) { - Objects.requireNonNull(template); - try { - NetworkStats stats = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - Bucket bucket = stats.getDeviceSummaryForNetwork(); - stats.close(); - return bucket; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return null; // To make the compiler happy. - } - - /** - * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and - * roaming. This means the bucket's start and end timestamp are going to be the same as the - * 'startTime' and 'endTime' parameters. State is going to be - * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, - * tag {@link NetworkStats.Bucket#TAG_NONE}, - * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, - * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Bucket object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public Bucket querySummaryForDevice(int networkType, @Nullable String subscriberId, - long startTime, long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - return querySummaryForDevice(template, startTime, endTime); - } - - /** - * Query network usage statistics summaries. Result is summarised data usage for all uids - * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. - * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, - * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming - * {@link NetworkStats.Bucket#ROAMING_ALL}. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Bucket object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public Bucket querySummaryForUser(int networkType, @Nullable String subscriberId, - long startTime, long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - NetworkStats stats; - stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - stats.startSummaryEnumeration(); - - stats.close(); - return stats.getSummaryAggregate(); - } - - /** - * Query network usage statistics summaries. Result filtered to include only uids belonging to - * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This - * means buckets' start and end timestamps are going to be the same as the 'startTime' and - * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to - * be the same. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public NetworkStats querySummary(int networkType, @Nullable String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - return querySummary(template, startTime, endTime); - } - - /** - * Query network usage statistics summaries. - * - * The results will only include traffic made by UIDs belonging to the calling user profile. - * The results are aggregated over time, so that all buckets will have the same start and - * end timestamps as the passed arguments. Not aggregated over state, uid, default network, - * metered, or roaming. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime, - long endTime) throws SecurityException { - Objects.requireNonNull(template); - try { - NetworkStats result = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startSummaryEnumeration(); - return result; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return null; // To make the compiler happy. - } - - /** - * Query tagged network usage statistics summaries. - * - * The results will only include tagged traffic made by UIDs belonging to the calling user - * profile. The results are aggregated over time, so that all buckets will have the same - * start and end timestamps as the passed arguments. Not aggregated over state, uid, - * default network, metered, or roaming. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link System#currentTimeMillis}. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats queryTaggedSummary(@NonNull NetworkTemplate template, long startTime, - long endTime) throws SecurityException { - Objects.requireNonNull(template); - try { - NetworkStats result = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startTaggedSummaryEnumeration(); - return result; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return null; // To make the compiler happy. - } - - /** - * Query usage statistics details for networks matching a given {@link NetworkTemplate}. - * - * Result is not aggregated over time. This means buckets' start and - * end timestamps will be between 'startTime' and 'endTime' parameters. - * <p>Only includes buckets whose entire time period is included between - * startTime and endTime. Doesn't interpolate or return partial buckets. - * Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats queryDetailsForDevice(@NonNull NetworkTemplate template, - long startTime, long endTime) { - Objects.requireNonNull(template); - try { - final NetworkStats result = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startHistoryDeviceEnumeration(); - return result; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - - return null; // To make the compiler happy. - } - - /** - * Query network usage statistics details for a given uid. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) - */ - @NonNull - @WorkerThread - public NetworkStats queryDetailsForUid(int networkType, @Nullable String subscriberId, - long startTime, long endTime, int uid) throws SecurityException { - return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, - NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); - } - - /** @hide */ - @NonNull - public NetworkStats queryDetailsForUid(@NonNull NetworkTemplate template, - long startTime, long endTime, int uid) throws SecurityException { - return queryDetailsForUidTagState(template, startTime, endTime, uid, - NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); - } - - /** - * Query network usage statistics details for a given uid and tag. - * - * This may take a long time, and apps should avoid calling this on their main thread. - * Only usable for uids belonging to calling user. Result is not aggregated over time. - * This means buckets' start and end timestamps are going to be between 'startTime' and - * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag - * the same as the 'tag' parameter, and the state the same as the 'state' parameter. - * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and - * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. - * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param uid UID of app - * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data - * across all the tags. - * @return Statistics which is described above. - * @throws SecurityException if permissions are insufficient to read network statistics. - */ - @NonNull - @WorkerThread - public NetworkStats queryDetailsForUidTag(int networkType, @Nullable String subscriberId, - long startTime, long endTime, int uid, int tag) throws SecurityException { - return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, - tag, NetworkStats.Bucket.STATE_ALL); - } - - /** - * Query network usage statistics details for a given uid, tag, and state. - * - * Only usable for uids belonging to calling user. Result is not aggregated over time. - * This means buckets' start and end timestamps are going to be between 'startTime' and - * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag - * the same as the 'tag' parameter, and the state the same as the 'state' parameter. - * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and - * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. - * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param uid UID of app - * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data - * across all the tags. - * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate - * traffic from all states. - * @return Statistics which is described above. - * @throws SecurityException if permissions are insufficient to read network statistics. - */ - @NonNull - @WorkerThread - public NetworkStats queryDetailsForUidTagState(int networkType, @Nullable String subscriberId, - long startTime, long endTime, int uid, int tag, int state) throws SecurityException { - NetworkTemplate template; - template = createTemplate(networkType, subscriberId); - - return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state); - } - - /** - * Query network usage statistics details for a given template, uid, tag, and state. - * - * Only usable for uids belonging to calling user. Result is not aggregated over time. - * This means buckets' start and end timestamps are going to be between 'startTime' and - * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag - * the same as the 'tag' parameter, and the state the same as the 'state' parameter. - * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and - * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. - * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param uid UID of app - * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data - * across all the tags. - * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate - * traffic from all states. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats queryDetailsForUidTagState(@NonNull NetworkTemplate template, - long startTime, long endTime, int uid, int tag, int state) throws SecurityException { - Objects.requireNonNull(template); - try { - final NetworkStats result = new NetworkStats( - mContext, template, mFlags, startTime, endTime, mService); - result.startHistoryUidEnumeration(uid, tag, state); - return result; - } catch (RemoteException e) { - Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag - + " state=" + state, e); - e.rethrowFromSystemServer(); - } - - return null; // To make the compiler happy. - } - - /** - * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time, uid, tag, - * metered, nor roaming. This means buckets' start and end timestamps are going to be between - * 'startTime' and 'endTime' parameters. State is going to be - * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE}, - * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, - * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. - * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public NetworkStats queryDetails(int networkType, @Nullable String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - NetworkStats result; - result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startUserUidEnumeration(); - return result; - } - - /** - * Query realtime mobile network usage statistics. - * - * Return a snapshot of current UID network statistics, as it applies - * to the mobile radios of the device. The snapshot will include any - * tethering traffic, video calling data usage and count of - * network operations set by {@link TrafficStats#incrementOperationCount} - * made over a mobile radio. - * The snapshot will not include any statistics that cannot be seen by - * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - @NonNull public android.net.NetworkStats getMobileUidStats() { - try { - return mService.getUidStatsForTransport(TRANSPORT_CELLULAR); - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when get Mobile uid stats"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Query realtime Wi-Fi network usage statistics. - * - * Return a snapshot of current UID network statistics, as it applies - * to the Wi-Fi radios of the device. The snapshot will include any - * tethering traffic, video calling data usage and count of - * network operations set by {@link TrafficStats#incrementOperationCount} - * made over a Wi-Fi radio. - * The snapshot will not include any statistics that cannot be seen by - * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - @NonNull public android.net.NetworkStats getWifiUidStats() { - try { - return mService.getUidStatsForTransport(TRANSPORT_WIFI); - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when get WiFi uid stats"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Registers to receive notifications about data usage on specified networks. - * - * <p>The callbacks will continue to be called as long as the process is alive or - * {@link #unregisterUsageCallback} is called. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB - * will be clamped for callers except callers with the NETWORK_STACK - * permission. - * @param executor The executor on which callback will be invoked. The provided {@link Executor} - * must run callback sequentially, otherwise the order of callbacks cannot be - * guaranteed. - * @param callback The {@link UsageCallback} that the system will call when data usage - * has exceeded the specified threshold. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}, conditional = true) - public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes, - @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) { - Objects.requireNonNull(template, "NetworkTemplate cannot be null"); - Objects.requireNonNull(callback, "UsageCallback cannot be null"); - Objects.requireNonNull(executor, "Executor cannot be null"); - - final DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, - template, thresholdBytes); - try { - final UsageCallbackWrapper callbackWrapper = - new UsageCallbackWrapper(executor, callback); - callback.request = mService.registerUsageCallback( - mContext.getOpPackageName(), request, callbackWrapper); - if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); - - if (callback.request == null) { - Log.e(TAG, "Request from callback is null; should not happen"); - } - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when registering callback"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Registers to receive notifications about data usage on specified networks. - * - * <p>The callbacks will continue to be called as long as the process is live or - * {@link #unregisterUsageCallback} is called. - * - * @param networkType Type of network to monitor. Either - {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when registering for the mobile network type to receive - * notifications for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param thresholdBytes Threshold in bytes to be notified on. - * @param callback The {@link UsageCallback} that the system will call when data usage - * has exceeded the specified threshold. - */ - public void registerUsageCallback(int networkType, @Nullable String subscriberId, - long thresholdBytes, @NonNull UsageCallback callback) { - registerUsageCallback(networkType, subscriberId, thresholdBytes, callback, - null /* handler */); - } - - /** - * Registers to receive notifications about data usage on specified networks. - * - * <p>The callbacks will continue to be called as long as the process is live or - * {@link #unregisterUsageCallback} is called. - * - * @param networkType Type of network to monitor. Either - {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. - * @param subscriberId If applicable, the subscriber id of the network interface. - * <p>Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when registering for the mobile network type to receive - * notifications for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - * <p>Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param thresholdBytes Threshold in bytes to be notified on. - * @param callback The {@link UsageCallback} that the system will call when data usage - * has exceeded the specified threshold. - * @param handler to dispatch callback events through, otherwise if {@code null} it uses - * the calling thread. - */ - public void registerUsageCallback(int networkType, @Nullable String subscriberId, - long thresholdBytes, @NonNull UsageCallback callback, @Nullable Handler handler) { - NetworkTemplate template = createTemplate(networkType, subscriberId); - if (DBG) { - Log.d(TAG, "registerUsageCallback called with: {" - + " networkType=" + networkType - + " subscriberId=" + subscriberId - + " thresholdBytes=" + thresholdBytes - + " }"); - } - - final Executor executor = handler == null ? r -> r.run() : r -> handler.post(r); - - registerUsageCallback(template, thresholdBytes, executor, callback); - } - - /** - * Unregisters callbacks on data usage. - * - * @param callback The {@link UsageCallback} used when registering. - */ - public void unregisterUsageCallback(@NonNull UsageCallback callback) { - if (callback == null || callback.request == null - || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { - throw new IllegalArgumentException("Invalid UsageCallback"); - } - try { - mService.unregisterUsageRequest(callback.request); - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Base class for usage callbacks. Should be extended by applications wanting notifications. - */ - public static abstract class UsageCallback { - /** - * Called when data usage has reached the given threshold. - * - * Called by {@code NetworkStatsService} when the registered threshold is reached. - * If a caller implements {@link #onThresholdReached(NetworkTemplate)}, the system - * will not call {@link #onThresholdReached(int, String)}. - * - * @param template The {@link NetworkTemplate} that associated with this callback. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public void onThresholdReached(@NonNull NetworkTemplate template) { - // Backward compatibility for those who didn't override this function. - final int networkType = networkTypeForTemplate(template); - if (networkType != ConnectivityManager.TYPE_NONE) { - final String subscriberId = template.getSubscriberIds().isEmpty() ? null - : template.getSubscriberIds().iterator().next(); - onThresholdReached(networkType, subscriberId); - } - } - - /** - * Called when data usage has reached the given threshold. - */ - public abstract void onThresholdReached(int networkType, @Nullable String subscriberId); - - /** - * @hide used for internal bookkeeping - */ - private DataUsageRequest request; - - /** - * Get network type from a template if feasible. - * - * @param template the target {@link NetworkTemplate}. - * @return legacy network type, only supports for the types which is already supported in - * {@link #registerUsageCallback(int, String, long, UsageCallback, Handler)}. - * {@link ConnectivityManager#TYPE_NONE} for other types. - */ - private static int networkTypeForTemplate(@NonNull NetworkTemplate template) { - switch (template.getMatchRule()) { - case NetworkTemplate.MATCH_MOBILE: - return ConnectivityManager.TYPE_MOBILE; - case NetworkTemplate.MATCH_WIFI: - return ConnectivityManager.TYPE_WIFI; - default: - return ConnectivityManager.TYPE_NONE; - } - } - } - - /** - * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics - * to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}. - * Note that no de-duplication of statistics between providers is performed, so each provider - * must only report network traffic that is not being reported by any other provider. Also note - * that the provider cannot be re-registered after unregistering. - * - * @param tag a human readable identifier of the custom network stats provider. This is only - * used for debugging. - * @param provider the subclass of {@link NetworkStatsProvider} that needs to be - * registered to the system. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STATS_PROVIDER, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - public void registerNetworkStatsProvider( - @NonNull String tag, - @NonNull NetworkStatsProvider provider) { - try { - if (provider.getProviderCallbackBinder() != null) { - throw new IllegalArgumentException("provider is already registered"); - } - final INetworkStatsProviderCallback cbBinder = - mService.registerNetworkStatsProvider(tag, provider.getProviderBinder()); - provider.setProviderCallbackBinder(cbBinder); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Unregisters an instance of {@link NetworkStatsProvider}. - * - * @param provider the subclass of {@link NetworkStatsProvider} that needs to be - * unregistered to the system. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STATS_PROVIDER, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) { - try { - provider.getProviderCallbackBinderOrThrow().unregister(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) { - final NetworkTemplate template; - switch (networkType) { - case ConnectivityManager.TYPE_MOBILE: - template = subscriberId == null - ? NetworkTemplate.buildTemplateMobileWildcard() - : NetworkTemplate.buildTemplateMobileAll(subscriberId); - break; - case ConnectivityManager.TYPE_WIFI: - template = TextUtils.isEmpty(subscriberId) - ? NetworkTemplate.buildTemplateWifiWildcard() - : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, - subscriberId); - break; - default: - throw new IllegalArgumentException("Cannot create template for network type " - + networkType + ", subscriberId '" - + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'."); - } - return template; - } - - /** - * Notify {@code NetworkStatsService} about network status changed. - * - * Notifies NetworkStatsService of network state changes for data usage accounting purposes. - * - * To avoid races that attribute data usage to wrong network, such as new network with - * the same interface after SIM hot-swap, this function will not return until - * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from - * all data sources. - * - * @param defaultNetworks the list of all networks that could be used by network traffic that - * does not explicitly select a network. - * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for - * each network that is currently connected. - * @param activeIface the active (i.e., connected) default network interface for the calling - * uid. Used to determine on which network future calls to - * {@link android.net.TrafficStats#incrementOperationCount} applies to. - * @param underlyingNetworkInfos the list of underlying network information for all - * currently-connected VPNs. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void notifyNetworkStatus( - @NonNull List<Network> defaultNetworks, - @NonNull List<NetworkStateSnapshot> networkStateSnapshots, - @Nullable String activeIface, - @NonNull List<UnderlyingNetworkInfo> underlyingNetworkInfos) { - try { - Objects.requireNonNull(defaultNetworks); - Objects.requireNonNull(networkStateSnapshots); - Objects.requireNonNull(underlyingNetworkInfos); - mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]), - networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, - underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private static class UsageCallbackWrapper extends IUsageCallback.Stub { - // Null if unregistered. - private volatile UsageCallback mCallback; - - private final Executor mExecutor; - - UsageCallbackWrapper(@NonNull Executor executor, @NonNull UsageCallback callback) { - mCallback = callback; - mExecutor = executor; - } - - @Override - public void onThresholdReached(DataUsageRequest request) { - // Copy it to a local variable in case mCallback changed inside the if condition. - final UsageCallback callback = mCallback; - if (callback != null) { - mExecutor.execute(() -> callback.onThresholdReached(request.template)); - } else { - Log.e(TAG, "onThresholdReached with released callback for " + request); - } - } - - @Override - public void onCallbackReleased(DataUsageRequest request) { - if (DBG) Log.d(TAG, "callback released for " + request); - mCallback = null; - } - } - - /** - * Mark given UID as being in foreground for stats purposes. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void noteUidForeground(int uid, boolean uidForeground) { - try { - mService.noteUidForeground(uid, uidForeground); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set default value of global alert bytes, the value will be clamped to [128kB, 2MB]. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - Manifest.permission.NETWORK_STACK}) - public void setDefaultGlobalAlert(long alertBytes) { - try { - // TODO: Sync internal naming with the API surface. - mService.advisePersistThreshold(alertBytes); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Force update of statistics. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void forceUpdate() { - try { - mService.forceUpdate(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set the warning and limit to all registered custom network stats providers. - * Note that invocation of any interface will be sent to all providers. - * - * Asynchronicity notes : because traffic may be happening on the device at the same time, it - * doesn't make sense to wait for the warning and limit to be set – a caller still wouldn't - * know when exactly it was effective. All that can matter is that it's done quickly. Also, - * this method can't fail, so there is no status to return. All providers will see the new - * values soon. - * As such, this method returns immediately and sends the warning and limit to all providers - * as soon as possible through a one-way binder call. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning, - long limit) { - try { - mService.setStatsProviderWarningAndLimitAsync(iface, warning, limit); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get a RAT type representative of a group of RAT types for network statistics. - * - * Collapse the given Radio Access Technology (RAT) type into a bucket that - * is representative of the original RAT type for network statistics. The - * mapping mostly corresponds to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*} - * but with adaptations specific to the virtual types introduced by - * networks stats. - * - * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static int getCollapsedRatType(int ratType) { - switch (ratType) { - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_GSM: - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_IDEN: - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_1xRTT: - return TelephonyManager.NETWORK_TYPE_GSM; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - case TelephonyManager.NETWORK_TYPE_EHRPD: - case TelephonyManager.NETWORK_TYPE_UMTS: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - case TelephonyManager.NETWORK_TYPE_TD_SCDMA: - return TelephonyManager.NETWORK_TYPE_UMTS; - case TelephonyManager.NETWORK_TYPE_LTE: - case TelephonyManager.NETWORK_TYPE_IWLAN: - return TelephonyManager.NETWORK_TYPE_LTE; - case TelephonyManager.NETWORK_TYPE_NR: - return TelephonyManager.NETWORK_TYPE_NR; - // Virtual RAT type for 5G NSA mode, see - // {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}. - case NetworkStatsManager.NETWORK_TYPE_5G_NSA: - return NetworkStatsManager.NETWORK_TYPE_5G_NSA; - default: - return TelephonyManager.NETWORK_TYPE_UNKNOWN; - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java deleted file mode 100644 index 61b34d0bcfe6..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ /dev/null @@ -1,82 +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.net; - -import android.annotation.SystemApi; -import android.app.SystemServiceRegistry; -import android.app.usage.NetworkStatsManager; -import android.content.Context; -import android.net.nsd.INsdManager; -import android.net.nsd.NsdManager; - -/** - * Class for performing registration for Connectivity services which are exposed via updatable APIs - * since Android T. - * - * @hide - */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public final class ConnectivityFrameworkInitializerTiramisu { - private ConnectivityFrameworkInitializerTiramisu() {} - - /** - * Called by {@link SystemServiceRegistry}'s static initializer and registers NetworkStats, nsd, - * ipsec and ethernet services to {@link Context}, so that {@link Context#getSystemService} can - * return them. - * - * @throws IllegalStateException if this is called anywhere besides - * {@link SystemServiceRegistry}. - */ - public static void registerServiceWrappers() { - SystemServiceRegistry.registerContextAwareService( - Context.NSD_SERVICE, - NsdManager.class, - (context, serviceBinder) -> { - INsdManager service = INsdManager.Stub.asInterface(serviceBinder); - return new NsdManager(context, service); - } - ); - - SystemServiceRegistry.registerContextAwareService( - Context.IPSEC_SERVICE, - IpSecManager.class, - (context, serviceBinder) -> { - IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder); - return new IpSecManager(context, service); - } - ); - - SystemServiceRegistry.registerContextAwareService( - Context.NETWORK_STATS_SERVICE, - NetworkStatsManager.class, - (context, serviceBinder) -> { - INetworkStatsService service = - INetworkStatsService.Stub.asInterface(serviceBinder); - return new NetworkStatsManager(context, service); - } - ); - - SystemServiceRegistry.registerContextAwareService( - Context.ETHERNET_SERVICE, - EthernetManager.class, - (context, serviceBinder) -> { - IEthernetManager service = IEthernetManager.Stub.asInterface(serviceBinder); - return new EthernetManager(context, service); - } - ); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl deleted file mode 100644 index d1937c7b8c62..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2016, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable DataUsageRequest; diff --git a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java deleted file mode 100644 index f0ff46522d15..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -package android.net; - -import android.annotation.Nullable; -import android.net.NetworkTemplate; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * Defines a request to register a callbacks. Used to be notified on data usage via - * {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}. - * If no {@code uid}s are set, callbacks are restricted to device-owners, - * carrier-privileged apps, or system apps. - * - * @hide - */ -public final class DataUsageRequest implements Parcelable { - - public static final String PARCELABLE_KEY = "DataUsageRequest"; - public static final int REQUEST_ID_UNSET = 0; - - /** - * Identifies the request. {@link DataUsageRequest}s should only be constructed by - * the Framework and it is used internally to identify the request. - */ - public final int requestId; - - /** - * {@link NetworkTemplate} describing the network to monitor. - */ - public final NetworkTemplate template; - - /** - * Threshold in bytes to be notified on. - */ - public final long thresholdInBytes; - - public DataUsageRequest(int requestId, NetworkTemplate template, long thresholdInBytes) { - this.requestId = requestId; - this.template = template; - this.thresholdInBytes = thresholdInBytes; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(requestId); - dest.writeParcelable(template, flags); - dest.writeLong(thresholdInBytes); - } - - public static final @android.annotation.NonNull Creator<DataUsageRequest> CREATOR = - new Creator<DataUsageRequest>() { - @Override - public DataUsageRequest createFromParcel(Parcel in) { - int requestId = in.readInt(); - NetworkTemplate template = in.readParcelable(null, android.net.NetworkTemplate.class); - long thresholdInBytes = in.readLong(); - DataUsageRequest result = new DataUsageRequest(requestId, template, - thresholdInBytes); - return result; - } - - @Override - public DataUsageRequest[] newArray(int size) { - return new DataUsageRequest[size]; - } - }; - - @Override - public String toString() { - return "DataUsageRequest [ requestId=" + requestId - + ", networkTemplate=" + template - + ", thresholdInBytes=" + thresholdInBytes + " ]"; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof DataUsageRequest == false) return false; - DataUsageRequest that = (DataUsageRequest) obj; - return that.requestId == this.requestId - && Objects.equals(that.template, this.template) - && that.thresholdInBytes == this.thresholdInBytes; - } - - @Override - public int hashCode() { - return Objects.hash(requestId, template, thresholdInBytes); - } - -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java deleted file mode 100644 index e02ea897dbe6..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java +++ /dev/null @@ -1,729 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.CallbackExecutor; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresFeature; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.OutcomeReceiver; -import android.os.RemoteException; - -import com.android.internal.annotations.GuardedBy; -import com.android.modules.utils.BackgroundThread; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.function.IntConsumer; - -/** - * A class that manages and configures Ethernet interfaces. - * - * @hide - */ -@SystemApi -@SystemService(Context.ETHERNET_SERVICE) -public class EthernetManager { - private static final String TAG = "EthernetManager"; - - private final IEthernetManager mService; - @GuardedBy("mListenerLock") - private final ArrayList<ListenerInfo<InterfaceStateListener>> mIfaceListeners = - new ArrayList<>(); - @GuardedBy("mListenerLock") - private final ArrayList<ListenerInfo<IntConsumer>> mEthernetStateListeners = - new ArrayList<>(); - final Object mListenerLock = new Object(); - private final IEthernetServiceListener.Stub mServiceListener = - new IEthernetServiceListener.Stub() { - @Override - public void onEthernetStateChanged(int state) { - synchronized (mListenerLock) { - for (ListenerInfo<IntConsumer> li : mEthernetStateListeners) { - li.executor.execute(() -> { - li.listener.accept(state); - }); - } - } - } - - @Override - public void onInterfaceStateChanged(String iface, int state, int role, - IpConfiguration configuration) { - synchronized (mListenerLock) { - for (ListenerInfo<InterfaceStateListener> li : mIfaceListeners) { - li.executor.execute(() -> - li.listener.onInterfaceStateChanged(iface, state, role, - configuration)); - } - } - } - }; - - /** - * Indicates that Ethernet is disabled. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ETHERNET_STATE_DISABLED = 0; - - /** - * Indicates that Ethernet is enabled. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ETHERNET_STATE_ENABLED = 1; - - private static class ListenerInfo<T> { - @NonNull - public final Executor executor; - @NonNull - public final T listener; - - private ListenerInfo(@NonNull Executor executor, @NonNull T listener) { - this.executor = executor; - this.listener = listener; - } - } - - /** - * The interface is absent. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int STATE_ABSENT = 0; - - /** - * The interface is present but link is down. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int STATE_LINK_DOWN = 1; - - /** - * The interface is present and link is up. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int STATE_LINK_UP = 2; - - /** @hide */ - @IntDef(prefix = "STATE_", value = {STATE_ABSENT, STATE_LINK_DOWN, STATE_LINK_UP}) - @Retention(RetentionPolicy.SOURCE) - public @interface InterfaceState {} - - /** - * The interface currently does not have any specific role. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ROLE_NONE = 0; - - /** - * The interface is in client mode (e.g., connected to the Internet). - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ROLE_CLIENT = 1; - - /** - * Ethernet interface is in server mode (e.g., providing Internet access to tethered devices). - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ROLE_SERVER = 2; - - /** @hide */ - @IntDef(prefix = "ROLE_", value = {ROLE_NONE, ROLE_CLIENT, ROLE_SERVER}) - @Retention(RetentionPolicy.SOURCE) - public @interface Role {} - - /** - * A listener that receives notifications about the state of Ethernet interfaces on the system. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public interface InterfaceStateListener { - /** - * Called when an Ethernet interface changes state. - * - * @param iface the name of the interface. - * @param state the current state of the interface, or {@link #STATE_ABSENT} if the - * interface was removed. - * @param role whether the interface is in client mode or server mode. - * @param configuration the current IP configuration of the interface. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, - @Role int role, @Nullable IpConfiguration configuration); - } - - /** - * A listener interface to receive notification on changes in Ethernet. - * This has never been a supported API. Use {@link InterfaceStateListener} instead. - * @hide - */ - public interface Listener extends InterfaceStateListener { - /** - * Called when Ethernet port's availability is changed. - * @param iface Ethernet interface name - * @param isAvailable {@code true} if Ethernet port exists. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - void onAvailabilityChanged(String iface, boolean isAvailable); - - /** Default implementation for backwards compatibility. Only calls the legacy listener. */ - default void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, - @Role int role, @Nullable IpConfiguration configuration) { - onAvailabilityChanged(iface, (state >= STATE_LINK_UP)); - } - - } - - /** - * Create a new EthernetManager instance. - * Applications will almost always want to use - * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve - * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. - * @hide - */ - public EthernetManager(Context context, IEthernetManager service) { - mService = service; - } - - /** - * Get Ethernet configuration. - * @return the Ethernet Configuration, contained in {@link IpConfiguration}. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public IpConfiguration getConfiguration(String iface) { - try { - return mService.getConfiguration(iface); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set Ethernet configuration. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void setConfiguration(@NonNull String iface, @NonNull IpConfiguration config) { - try { - mService.setConfiguration(iface, config); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Indicates whether the system currently has one or more Ethernet interfaces. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean isAvailable() { - return getAvailableInterfaces().length > 0; - } - - /** - * Indicates whether the system has given interface. - * - * @param iface Ethernet interface name - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean isAvailable(String iface) { - try { - return mService.isAvailable(iface); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Adds a listener. - * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. - * - * @param listener A {@link Listener} to add. - * @throws IllegalArgumentException If the listener is null. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void addListener(@NonNull Listener listener) { - addListener(listener, BackgroundThread.getExecutor()); - } - - /** - * Adds a listener. - * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. - * - * @param listener A {@link Listener} to add. - * @param executor Executor to run callbacks on. - * @throws IllegalArgumentException If the listener or executor is null. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void addListener(@NonNull Listener listener, @NonNull Executor executor) { - addInterfaceStateListener(executor, listener); - } - - /** - * Listen to changes in the state of Ethernet interfaces. - * - * Adds a listener to receive notification for any state change of all existing Ethernet - * interfaces. - * <p>{@link Listener#onInterfaceStateChanged} will be triggered immediately for all - * existing interfaces upon adding a listener. The same method will be called on the - * listener every time any of the interface changes state. In particular, if an - * interface is removed, it will be called with state {@link #STATE_ABSENT}. - * <p>Use {@link #removeInterfaceStateListener} with the same object to stop listening. - * - * @param executor Executor to run callbacks on. - * @param listener A {@link Listener} to add. - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - public void addInterfaceStateListener(@NonNull Executor executor, - @NonNull InterfaceStateListener listener) { - if (listener == null || executor == null) { - throw new NullPointerException("listener and executor must not be null"); - } - synchronized (mListenerLock) { - maybeAddServiceListener(); - mIfaceListeners.add(new ListenerInfo<InterfaceStateListener>(executor, listener)); - } - } - - @GuardedBy("mListenerLock") - private void maybeAddServiceListener() { - if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; - - try { - mService.addListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - - } - - /** - * Returns an array of available Ethernet interface names. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String[] getAvailableInterfaces() { - try { - return mService.getAvailableInterfaces(); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - - /** - * Removes a listener. - * - * @param listener A {@link Listener} to remove. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { - Objects.requireNonNull(listener); - synchronized (mListenerLock) { - mIfaceListeners.removeIf(l -> l.listener == listener); - maybeRemoveServiceListener(); - } - } - - @GuardedBy("mListenerLock") - private void maybeRemoveServiceListener() { - if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; - - try { - mService.removeListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Removes a listener. - * This has never been a supported API. Use {@link #removeInterfaceStateListener} instead. - * @param listener A {@link Listener} to remove. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void removeListener(@NonNull Listener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - removeInterfaceStateListener(listener); - } - - /** - * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} - * as Ethernet interfaces. The effects of this method apply to any test interfaces that are - * already present on the system. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public void setIncludeTestInterfaces(boolean include) { - try { - mService.setIncludeTestInterfaces(include); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * A request for a tethered interface. - */ - public static class TetheredInterfaceRequest { - private final IEthernetManager mService; - private final ITetheredInterfaceCallback mCb; - - private TetheredInterfaceRequest(@NonNull IEthernetManager service, - @NonNull ITetheredInterfaceCallback cb) { - this.mService = service; - this.mCb = cb; - } - - /** - * Release the request, causing the interface to revert back from tethering mode if there - * is no other requestor. - */ - public void release() { - try { - mService.releaseTetheredInterface(mCb); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - } - - /** - * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}. - */ - public interface TetheredInterfaceCallback { - /** - * Called when the tethered interface is available. - * @param iface The name of the interface. - */ - void onAvailable(@NonNull String iface); - - /** - * Called when the tethered interface is now unavailable. - */ - void onUnavailable(); - } - - /** - * Request a tethered interface in tethering mode. - * - * <p>When this method is called and there is at least one ethernet interface available, the - * system will designate one to act as a tethered interface. If there is already a tethered - * interface, the existing interface will be used. - * @param callback A callback to be called once the request has been fulfilled. - */ - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, - android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK - }) - @NonNull - public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor, - @NonNull final TetheredInterfaceCallback callback) { - Objects.requireNonNull(callback, "Callback must be non-null"); - Objects.requireNonNull(executor, "Executor must be non-null"); - final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { - @Override - public void onAvailable(String iface) { - executor.execute(() -> callback.onAvailable(iface)); - } - - @Override - public void onUnavailable() { - executor.execute(() -> callback.onUnavailable()); - } - }; - - try { - mService.requestTetheredInterface(cbInternal); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return new TetheredInterfaceRequest(mService, cbInternal); - } - - private static final class NetworkInterfaceOutcomeReceiver - extends INetworkInterfaceOutcomeReceiver.Stub { - @NonNull - private final Executor mExecutor; - @NonNull - private final OutcomeReceiver<String, EthernetNetworkManagementException> mCallback; - - NetworkInterfaceOutcomeReceiver( - @NonNull final Executor executor, - @NonNull final OutcomeReceiver<String, EthernetNetworkManagementException> - callback) { - Objects.requireNonNull(executor, "Pass a non-null executor"); - Objects.requireNonNull(callback, "Pass a non-null callback"); - mExecutor = executor; - mCallback = callback; - } - - @Override - public void onResult(@NonNull String iface) { - mExecutor.execute(() -> mCallback.onResult(iface)); - } - - @Override - public void onError(@NonNull EthernetNetworkManagementException e) { - mExecutor.execute(() -> mCallback.onError(e)); - } - } - - private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver( - @Nullable final Executor executor, - @Nullable final OutcomeReceiver<String, EthernetNetworkManagementException> callback) { - if (null != callback) { - Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback"); - } - final NetworkInterfaceOutcomeReceiver proxy; - if (null == callback) { - proxy = null; - } else { - proxy = new NetworkInterfaceOutcomeReceiver(executor, callback); - } - return proxy; - } - - /** - * Updates the configuration of an automotive device's ethernet network. - * - * The {@link EthernetNetworkUpdateRequest} {@code request} argument describes how to update the - * configuration for this network. - * Use {@link StaticIpConfiguration.Builder} to build a {@code StaticIpConfiguration} object for - * this network to put inside the {@code request}. - * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} - * object for this network to put inside the {@code request}. - * - * This function accepts an {@link OutcomeReceiver} that is called once the operation has - * finished execution. - * - * @param iface the name of the interface to act upon. - * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's - * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. - * @throws SecurityException if the process doesn't hold - * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device or on an - * unsupported interface. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) - public void updateConfiguration( - @NonNull String iface, - @NonNull EthernetNetworkUpdateRequest request, - @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) { - Objects.requireNonNull(iface, "iface must be non-null"); - Objects.requireNonNull(request, "request must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); - try { - mService.updateConfiguration(iface, request, proxy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Enable a network interface. - * - * Enables a previously disabled network interface. - * This function accepts an {@link OutcomeReceiver} that is called once the operation has - * finished execution. - * - * @param iface the name of the interface to enable. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. - * @throws SecurityException if the process doesn't hold - * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) - @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void enableInterface( - @NonNull String iface, - @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) { - Objects.requireNonNull(iface, "iface must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); - try { - mService.connectNetwork(iface, proxy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Disable a network interface. - * - * Disables the use of a network interface to fulfill network requests. If the interface - * currently serves a request, the network will be torn down. - * This function accepts an {@link OutcomeReceiver} that is called once the operation has - * finished execution. - * - * @param iface the name of the interface to disable. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. - * @throws SecurityException if the process doesn't hold - * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) - @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void disableInterface( - @NonNull String iface, - @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) { - Objects.requireNonNull(iface, "iface must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); - try { - mService.disconnectNetwork(iface, proxy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Change ethernet setting. - * - * @param enabled enable or disable ethernet settings. - * - * @hide - */ - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.NETWORK_SETTINGS}) - @SystemApi(client = MODULE_LIBRARIES) - public void setEthernetEnabled(boolean enabled) { - try { - mService.setEthernetEnabled(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Listen to changes in the state of ethernet. - * - * @param executor to run callbacks on. - * @param listener to listen ethernet state changed. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - public void addEthernetStateListener(@NonNull Executor executor, - @NonNull IntConsumer listener) { - Objects.requireNonNull(executor); - Objects.requireNonNull(listener); - synchronized (mListenerLock) { - maybeAddServiceListener(); - mEthernetStateListeners.add(new ListenerInfo<IntConsumer>(executor, listener)); - } - } - - /** - * Removes a listener. - * - * @param listener to listen ethernet state changed. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - public void removeEthernetStateListener(@NonNull IntConsumer listener) { - Objects.requireNonNull(listener); - synchronized (mListenerLock) { - mEthernetStateListeners.removeIf(l -> l.listener == listener); - maybeRemoveServiceListener(); - } - } - - /** - * Returns an array of existing Ethernet interface names regardless whether the interface - * is available or not currently. - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - @NonNull - public List<String> getInterfaceList() { - try { - return mService.getInterfaceList(); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl deleted file mode 100644 index adf9e5a4db9d..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl +++ /dev/null @@ -1,19 +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.net; - - parcelable EthernetNetworkManagementException;
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java deleted file mode 100644 index a69cc55363b2..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java +++ /dev/null @@ -1,73 +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.net; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** @hide */ -@SystemApi -public final class EthernetNetworkManagementException - extends RuntimeException implements Parcelable { - - /* @hide */ - public EthernetNetworkManagementException(@NonNull final String errorMessage) { - super(errorMessage); - } - - @Override - public int hashCode() { - return Objects.hash(getMessage()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - final EthernetNetworkManagementException that = (EthernetNetworkManagementException) obj; - - return Objects.equals(getMessage(), that.getMessage()); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(getMessage()); - } - - @Override - public int describeContents() { - return 0; - } - - @NonNull - public static final Parcelable.Creator<EthernetNetworkManagementException> CREATOR = - new Parcelable.Creator<EthernetNetworkManagementException>() { - @Override - public EthernetNetworkManagementException[] newArray(int size) { - return new EthernetNetworkManagementException[size]; - } - - @Override - public EthernetNetworkManagementException createFromParcel(@NonNull Parcel source) { - return new EthernetNetworkManagementException(source.readString()); - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java deleted file mode 100644 index e4d6e248d48a..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java +++ /dev/null @@ -1,102 +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.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import java.util.Objects; - -/** - * A {@link NetworkSpecifier} used to identify ethernet interfaces. - * - * @see EthernetManager - */ -public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable { - - /** - * Name of the network interface. - */ - @NonNull - private final String mInterfaceName; - - /** - * Create a new EthernetNetworkSpecifier. - * @param interfaceName Name of the ethernet interface the specifier refers to. - */ - public EthernetNetworkSpecifier(@NonNull String interfaceName) { - if (TextUtils.isEmpty(interfaceName)) { - throw new IllegalArgumentException(); - } - mInterfaceName = interfaceName; - } - - /** - * Get the name of the ethernet interface the specifier refers to. - */ - @Nullable - public String getInterfaceName() { - // This may be null in the future to support specifiers based on data other than the - // interface name. - return mInterfaceName; - } - - /** @hide */ - @Override - public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { - return equals(other); - } - - @Override - public boolean equals(@Nullable Object o) { - if (!(o instanceof EthernetNetworkSpecifier)) return false; - return TextUtils.equals(mInterfaceName, ((EthernetNetworkSpecifier) o).mInterfaceName); - } - - @Override - public int hashCode() { - return Objects.hashCode(mInterfaceName); - } - - @Override - public String toString() { - return "EthernetNetworkSpecifier (" + mInterfaceName + ")"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(mInterfaceName); - } - - public static final @NonNull Parcelable.Creator<EthernetNetworkSpecifier> CREATOR = - new Parcelable.Creator<EthernetNetworkSpecifier>() { - public EthernetNetworkSpecifier createFromParcel(Parcel in) { - return new EthernetNetworkSpecifier(in.readString()); - } - public EthernetNetworkSpecifier[] newArray(int size) { - return new EthernetNetworkSpecifier[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl deleted file mode 100644 index debc348ea363..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl +++ /dev/null @@ -1,19 +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.net; - - parcelable EthernetNetworkUpdateRequest;
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java deleted file mode 100644 index 1691942c3675..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ /dev/null @@ -1,185 +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.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * Represents a request to update an existing Ethernet interface. - * - * @see EthernetManager#updateConfiguration - * - * @hide - */ -@SystemApi -public final class EthernetNetworkUpdateRequest implements Parcelable { - @Nullable - private final IpConfiguration mIpConfig; - @Nullable - private final NetworkCapabilities mNetworkCapabilities; - - /** - * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}. - * When set to null, the existing IpConfiguration is not updated. - * - * @return the new {@link IpConfiguration} or null. - */ - @Nullable - public IpConfiguration getIpConfiguration() { - return mIpConfig == null ? null : new IpConfiguration(mIpConfig); - } - - /** - * Setting the {@link NetworkCapabilities} is optional in {@link EthernetNetworkUpdateRequest}. - * When set to null, the existing NetworkCapabilities are not updated. - * - * @return the new {@link NetworkCapabilities} or null. - */ - @Nullable - public NetworkCapabilities getNetworkCapabilities() { - return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities); - } - - private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig, - @Nullable final NetworkCapabilities networkCapabilities) { - mIpConfig = ipConfig; - mNetworkCapabilities = networkCapabilities; - } - - private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { - Objects.requireNonNull(source); - mIpConfig = source.readParcelable(IpConfiguration.class.getClassLoader(), - IpConfiguration.class); - mNetworkCapabilities = source.readParcelable(NetworkCapabilities.class.getClassLoader(), - NetworkCapabilities.class); - } - - /** - * Builder used to create {@link EthernetNetworkUpdateRequest} objects. - */ - public static final class Builder { - @Nullable - private IpConfiguration mBuilderIpConfig; - @Nullable - private NetworkCapabilities mBuilderNetworkCapabilities; - - public Builder(){} - - /** - * Constructor to populate the builder's values with an already built - * {@link EthernetNetworkUpdateRequest}. - * @param request the {@link EthernetNetworkUpdateRequest} to populate with. - */ - public Builder(@NonNull final EthernetNetworkUpdateRequest request) { - Objects.requireNonNull(request); - mBuilderIpConfig = null == request.mIpConfig - ? null : new IpConfiguration(request.mIpConfig); - mBuilderNetworkCapabilities = null == request.mNetworkCapabilities - ? null : new NetworkCapabilities(request.mNetworkCapabilities); - } - - /** - * Set the {@link IpConfiguration} to be used with the {@code Builder}. - * @param ipConfig the {@link IpConfiguration} to set. - * @return The builder to facilitate chaining. - */ - @NonNull - public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) { - mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig); - return this; - } - - /** - * Set the {@link NetworkCapabilities} to be used with the {@code Builder}. - * @param nc the {@link NetworkCapabilities} to set. - * @return The builder to facilitate chaining. - */ - @NonNull - public Builder setNetworkCapabilities(@Nullable final NetworkCapabilities nc) { - mBuilderNetworkCapabilities = nc == null ? null : new NetworkCapabilities(nc); - return this; - } - - /** - * Build {@link EthernetNetworkUpdateRequest} return the current update request. - * - * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig - * are null. - */ - @NonNull - public EthernetNetworkUpdateRequest build() { - if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) { - throw new IllegalStateException( - "Cannot construct an empty EthernetNetworkUpdateRequest"); - } - return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities); - } - } - - @Override - public String toString() { - return "EthernetNetworkUpdateRequest{" - + "mIpConfig=" + mIpConfig - + ", mNetworkCapabilities=" + mNetworkCapabilities + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; - - return Objects.equals(that.getIpConfiguration(), mIpConfig) - && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); - } - - @Override - public int hashCode() { - return Objects.hash(mIpConfig, mNetworkCapabilities); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mIpConfig, flags); - dest.writeParcelable(mNetworkCapabilities, flags); - } - - @Override - public int describeContents() { - return 0; - } - - @NonNull - public static final Parcelable.Creator<EthernetNetworkUpdateRequest> CREATOR = - new Parcelable.Creator<EthernetNetworkUpdateRequest>() { - @Override - public EthernetNetworkUpdateRequest[] newArray(int size) { - return new EthernetNetworkUpdateRequest[size]; - } - - @Override - public EthernetNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { - return new EthernetNetworkUpdateRequest(source); - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl deleted file mode 100644 index 42e4c1ac55aa..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import android.net.IpConfiguration; -import android.net.IEthernetServiceListener; -import android.net.EthernetNetworkManagementException; -import android.net.EthernetNetworkUpdateRequest; -import android.net.INetworkInterfaceOutcomeReceiver; -import android.net.ITetheredInterfaceCallback; - -import java.util.List; - -/** - * Interface that answers queries about, and allows changing - * ethernet configuration. - */ -/** {@hide} */ -interface IEthernetManager -{ - String[] getAvailableInterfaces(); - IpConfiguration getConfiguration(String iface); - void setConfiguration(String iface, in IpConfiguration config); - boolean isAvailable(String iface); - void addListener(in IEthernetServiceListener listener); - void removeListener(in IEthernetServiceListener listener); - void setIncludeTestInterfaces(boolean include); - void requestTetheredInterface(in ITetheredInterfaceCallback callback); - void releaseTetheredInterface(in ITetheredInterfaceCallback callback); - void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, - in INetworkInterfaceOutcomeReceiver listener); - void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); - void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); - void setEthernetEnabled(boolean enabled); - List<String> getInterfaceList(); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl deleted file mode 100644 index 751605bb3849..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import android.net.IpConfiguration; - -/** @hide */ -oneway interface IEthernetServiceListener -{ - void onEthernetStateChanged(int state); - void onInterfaceStateChanged(String iface, int state, int role, - in IpConfiguration configuration); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl b/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl deleted file mode 100644 index 933256a3b475..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl +++ /dev/null @@ -1,78 +0,0 @@ -/* -** Copyright 2017, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -package android.net; - -import android.net.LinkAddress; -import android.net.Network; -import android.net.IpSecConfig; -import android.net.IpSecUdpEncapResponse; -import android.net.IpSecSpiResponse; -import android.net.IpSecTransformResponse; -import android.net.IpSecTunnelInterfaceResponse; -import android.os.Bundle; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; - -/** - * @hide - */ -interface IIpSecService -{ - IpSecSpiResponse allocateSecurityParameterIndex( - in String destinationAddress, int requestedSpi, in IBinder binder); - - void releaseSecurityParameterIndex(int resourceId); - - IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, in IBinder binder); - - void closeUdpEncapsulationSocket(int resourceId); - - IpSecTunnelInterfaceResponse createTunnelInterface( - in String localAddr, - in String remoteAddr, - in Network underlyingNetwork, - in IBinder binder, - in String callingPackage); - - void addAddressToTunnelInterface( - int tunnelResourceId, - in LinkAddress localAddr, - in String callingPackage); - - void removeAddressFromTunnelInterface( - int tunnelResourceId, - in LinkAddress localAddr, - in String callingPackage); - - void setNetworkForTunnelInterface( - int tunnelResourceId, in Network underlyingNetwork, in String callingPackage); - - void deleteTunnelInterface(int resourceId, in String callingPackage); - - IpSecTransformResponse createTransform( - in IpSecConfig c, in IBinder binder, in String callingPackage); - - void deleteTransform(int transformId); - - void applyTransportModeTransform( - in ParcelFileDescriptor socket, int direction, int transformId); - - void applyTunnelModeTransform( - int tunnelResourceId, int direction, int transformResourceId, in String callingPackage); - - void removeTransportModeTransforms(in ParcelFileDescriptor socket); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl deleted file mode 100644 index 85795ead7aea..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl +++ /dev/null @@ -1,25 +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.net; - -import android.net.EthernetNetworkManagementException; - -/** @hide */ -oneway interface INetworkInterfaceOutcomeReceiver { - void onResult(in String iface); - void onError(in EthernetNetworkManagementException e); -}
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl deleted file mode 100644 index c86f7fd0890d..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import android.net.DataUsageRequest; -import android.net.INetworkStatsSession; -import android.net.Network; -import android.net.NetworkStateSnapshot; -import android.net.NetworkStats; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.UnderlyingNetworkInfo; -import android.net.netstats.IUsageCallback; -import android.net.netstats.provider.INetworkStatsProvider; -import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.os.IBinder; -import android.os.Messenger; - -/** {@hide} */ -interface INetworkStatsService { - - /** Start a statistics query session. */ - @UnsupportedAppUsage - INetworkStatsSession openSession(); - - /** Start a statistics query session. If calling package is profile or device owner then it is - * granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If - * apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then - * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted - * READ_NETWORK_USAGE_STATS is checked for. - */ - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) - INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); - - /** Return data layer snapshot of UID network usage. */ - @UnsupportedAppUsage - NetworkStats getDataLayerSnapshotForUid(int uid); - - /** Get the transport NetworkStats for all UIDs since boot. */ - NetworkStats getUidStatsForTransport(int transport); - - /** Return set of any ifaces associated with mobile networks since boot. */ - @UnsupportedAppUsage - String[] getMobileIfaces(); - - /** Increment data layer count of operations performed for UID and tag. */ - void incrementOperationCount(int uid, int tag, int operationCount); - - /** Notify {@code NetworkStatsService} about network status changed. */ - void notifyNetworkStatus( - in Network[] defaultNetworks, - in NetworkStateSnapshot[] snapshots, - in String activeIface, - in UnderlyingNetworkInfo[] underlyingNetworkInfos); - /** Force update of statistics. */ - @UnsupportedAppUsage - void forceUpdate(); - - /** Registers a callback on data usage. */ - DataUsageRequest registerUsageCallback(String callingPackage, - in DataUsageRequest request, in IUsageCallback callback); - - /** Unregisters a callback on data usage. */ - void unregisterUsageRequest(in DataUsageRequest request); - - /** Get the uid stats information since boot */ - long getUidStats(int uid, int type); - - /** Get the iface stats information since boot */ - long getIfaceStats(String iface, int type); - - /** Get the total network stats information since boot */ - long getTotalStats(int type); - - /** Registers a network stats provider */ - INetworkStatsProviderCallback registerNetworkStatsProvider(String tag, - in INetworkStatsProvider provider); - - /** Mark given UID as being in foreground for stats purposes. */ - void noteUidForeground(int uid, boolean uidForeground); - - /** Advise persistence threshold; may be overridden internally. */ - void advisePersistThreshold(long thresholdBytes); - - /** - * Set the warning and limit to all registered custom network stats providers. - * Note that invocation of any interface will be sent to all providers. - */ - void setStatsProviderWarningAndLimitAsync(String iface, long warning, long limit); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl deleted file mode 100644 index ab70be826f8e..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import android.net.NetworkStats; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; - -/** {@hide} */ -interface INetworkStatsSession { - - /** Return device aggregated network layer usage summary for traffic that matches template. */ - NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end); - - /** Return network layer usage summary for traffic that matches template. */ - @UnsupportedAppUsage - NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); - /** Return historical network layer stats for traffic that matches template. */ - @UnsupportedAppUsage - NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); - /** - * Return historical network layer stats for traffic that matches template, start and end - * timestamp. - */ - NetworkStatsHistory getHistoryIntervalForNetwork(in NetworkTemplate template, int fields, long start, long end); - - /** - * Return network layer usage summary per UID for traffic that matches template. - * - * <p>The resulting {@code NetworkStats#getElapsedRealtime()} contains time delta between - * {@code start} and {@code end}. - * - * @param template - a predicate to filter netstats. - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param includeTags - includes data usage tags if true. - */ - @UnsupportedAppUsage - NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); - - /** Return network layer usage summary per UID for tagged traffic that matches template. */ - NetworkStats getTaggedSummaryForAllUid(in NetworkTemplate template, long start, long end); - - /** Return historical network layer stats for specific UID traffic that matches template. */ - @UnsupportedAppUsage - NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); - /** Return historical network layer stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryIntervalForUid(in NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end); - - /** Return array of uids that have stats and are accessible to the calling user */ - int[] getRelevantUids(); - - @UnsupportedAppUsage - void close(); - -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl deleted file mode 100644 index 14aa0237f24a..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl +++ /dev/null @@ -1,23 +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.net; - -/** @hide */ -oneway interface ITetheredInterfaceCallback { - void onAvailable(in String iface); - void onUnavailable(); -}
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java deleted file mode 100644 index 10a22ac360b1..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.annotation.NonNull; -import android.annotation.StringDef; -import android.content.res.Resources; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * This class represents a single algorithm that can be used by an {@link IpSecTransform}. - * - * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the - * Internet Protocol</a> - */ -public final class IpSecAlgorithm implements Parcelable { - private static final String TAG = "IpSecAlgorithm"; - - /** - * Null cipher. - * - * @hide - */ - public static final String CRYPT_NULL = "ecb(cipher_null)"; - - /** - * AES-CBC Encryption/Ciphering Algorithm. - * - * <p>Valid lengths for this key are {128, 192, 256}. - */ - public static final String CRYPT_AES_CBC = "cbc(aes)"; - - /** - * AES-CTR Encryption/Ciphering Algorithm. - * - * <p>Valid lengths for keying material are {160, 224, 288}. - * - * <p>As per <a href="https://tools.ietf.org/html/rfc3686#section-5.1">RFC3686 (Section - * 5.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit - * nonce. RFC compliance requires that the nonce must be unique per security association. - * - * <p>This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - * <p>@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))"; - - /** - * MD5 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in - * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b> - * - * <p>Keys for this algorithm must be 128 bits in length. - * - * <p>Valid truncation lengths are multiples of 8 bits from 96 to 128. - */ - public static final String AUTH_HMAC_MD5 = "hmac(md5)"; - - /** - * SHA1 HMAC Authentication/Integrity Algorithm. <b>This algorithm is not recommended for use in - * new applications and is provided for legacy compatibility with 3gpp infrastructure.</b> - * - * <p>Keys for this algorithm must be 160 bits in length. - * - * <p>Valid truncation lengths are multiples of 8 bits from 96 to 160. - */ - public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; - - /** - * SHA256 HMAC Authentication/Integrity Algorithm. - * - * <p>Keys for this algorithm must be 256 bits in length. - * - * <p>Valid truncation lengths are multiples of 8 bits from 96 to 256. - */ - public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; - - /** - * SHA384 HMAC Authentication/Integrity Algorithm. - * - * <p>Keys for this algorithm must be 384 bits in length. - * - * <p>Valid truncation lengths are multiples of 8 bits from 192 to 384. - */ - public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; - - /** - * SHA512 HMAC Authentication/Integrity Algorithm. - * - * <p>Keys for this algorithm must be 512 bits in length. - * - * <p>Valid truncation lengths are multiples of 8 bits from 256 to 512. - */ - public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; - - /** - * AES-XCBC Authentication/Integrity Algorithm. - * - * <p>Keys for this algorithm must be 128 bits in length. - * - * <p>The only valid truncation length is 96 bits. - * - * <p>This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - * <p>@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String AUTH_AES_XCBC = "xcbc(aes)"; - - /** - * AES-CMAC Authentication/Integrity Algorithm. - * - * <p>Keys for this algorithm must be 128 bits in length. - * - * <p>The only valid truncation length is 96 bits. - * - * <p>This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - * <p>@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String AUTH_AES_CMAC = "cmac(aes)"; - - /** - * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. - * - * <p>Valid lengths for keying material are {160, 224, 288}. - * - * <p>As per <a href="https://tools.ietf.org/html/rfc4106#section-8.1">RFC4106 (Section - * 8.1)</a>, keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit - * salt. RFC compliance requires that the salt must be unique per invocation with the same key. - * - * <p>Valid ICV (truncation) lengths are {64, 96, 128}. - */ - public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; - - /** - * ChaCha20-Poly1305 Authentication/Integrity + Encryption/Ciphering Algorithm. - * - * <p>Keys for this algorithm must be 288 bits in length. - * - * <p>As per <a href="https://tools.ietf.org/html/rfc7634#section-2">RFC7634 (Section 2)</a>, - * keying material consists of a 256 bit key followed by a 32-bit salt. The salt is fixed per - * security association. - * - * <p>The only valid ICV (truncation) length is 128 bits. - * - * <p>This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - * <p>@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; - - /** @hide */ - @StringDef({ - CRYPT_AES_CBC, - CRYPT_AES_CTR, - AUTH_HMAC_MD5, - AUTH_HMAC_SHA1, - AUTH_HMAC_SHA256, - AUTH_HMAC_SHA384, - AUTH_HMAC_SHA512, - AUTH_AES_XCBC, - AUTH_AES_CMAC, - AUTH_CRYPT_AES_GCM, - AUTH_CRYPT_CHACHA20_POLY1305 - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AlgorithmName {} - - /** @hide */ - @VisibleForTesting - public static final Map<String, Integer> ALGO_TO_REQUIRED_FIRST_SDK = new HashMap<>(); - - private static final int SDK_VERSION_ZERO = 0; - - static { - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); - - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S); - } - - private static final Set<String> ENABLED_ALGOS = - Collections.unmodifiableSet(loadAlgos(Resources.getSystem())); - - private final String mName; - private final byte[] mKey; - private final int mTruncLenBits; - - /** - * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are - * defined as constants in this class. - * - * <p>For algorithms that produce an integrity check value, the truncation length is a required - * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)} - * - * @param algorithm name of the algorithm. - * @param key key padded to a multiple of 8 bits. - * @throws IllegalArgumentException if algorithm or key length is invalid. - */ - public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { - this(algorithm, key, 0); - } - - /** - * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are - * defined as constants in this class. - * - * <p>This constructor only supports algorithms that use a truncation length. i.e. - * Authentication and Authenticated Encryption algorithms. - * - * @param algorithm name of the algorithm. - * @param key key padded to a multiple of 8 bits. - * @param truncLenBits number of bits of output hash to use. - * @throws IllegalArgumentException if algorithm, key length or truncation length is invalid. - */ - public IpSecAlgorithm( - @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { - mName = algorithm; - mKey = key.clone(); - mTruncLenBits = truncLenBits; - checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits); - } - - /** Get the algorithm name */ - @NonNull - public String getName() { - return mName; - } - - /** Get the key for this algorithm */ - @NonNull - public byte[] getKey() { - return mKey.clone(); - } - - /** Get the truncation length of this algorithm, in bits */ - public int getTruncationLengthBits() { - return mTruncLenBits; - } - - /** Parcelable Implementation */ - public int describeContents() { - return 0; - } - - /** Write to parcel */ - public void writeToParcel(Parcel out, int flags) { - out.writeString(mName); - out.writeByteArray(mKey); - out.writeInt(mTruncLenBits); - } - - /** Parcelable Creator */ - public static final @android.annotation.NonNull Parcelable.Creator<IpSecAlgorithm> CREATOR = - new Parcelable.Creator<IpSecAlgorithm>() { - public IpSecAlgorithm createFromParcel(Parcel in) { - final String name = in.readString(); - final byte[] key = in.createByteArray(); - final int truncLenBits = in.readInt(); - - return new IpSecAlgorithm(name, key, truncLenBits); - } - - public IpSecAlgorithm[] newArray(int size) { - return new IpSecAlgorithm[size]; - } - }; - - /** - * Returns supported IPsec algorithms for the current device. - * - * <p>Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is - * supported before using it. - */ - @NonNull - public static Set<String> getSupportedAlgorithms() { - return ENABLED_ALGOS; - } - - /** @hide */ - @VisibleForTesting - public static Set<String> loadAlgos(Resources systemResources) { - final Set<String> enabledAlgos = new HashSet<>(); - - // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in - // the resource are not allowed. - final String[] resourceAlgos = systemResources.getStringArray( - android.R.array.config_optionalIpSecAlgorithms); - for (String str : resourceAlgos) { - if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) { - // This error should be caught by CTS and never be thrown to API callers - throw new IllegalArgumentException("Invalid or repeated algorithm " + str); - } - } - - for (Entry<String, Integer> entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) { - if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= entry.getValue()) { - enabledAlgos.add(entry.getKey()); - } - } - - return enabledAlgos; - } - - private static void checkValidOrThrow(String name, int keyLen, int truncLen) { - final boolean isValidLen; - final boolean isValidTruncLen; - - if (!getSupportedAlgorithms().contains(name)) { - throw new IllegalArgumentException("Unsupported algorithm: " + name); - } - - switch (name) { - case CRYPT_AES_CBC: - isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256; - isValidTruncLen = true; - break; - case CRYPT_AES_CTR: - // The keying material for AES-CTR is a key plus a 32-bit salt - isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; - isValidTruncLen = true; - break; - case AUTH_HMAC_MD5: - isValidLen = keyLen == 128; - isValidTruncLen = truncLen >= 96 && truncLen <= 128; - break; - case AUTH_HMAC_SHA1: - isValidLen = keyLen == 160; - isValidTruncLen = truncLen >= 96 && truncLen <= 160; - break; - case AUTH_HMAC_SHA256: - isValidLen = keyLen == 256; - isValidTruncLen = truncLen >= 96 && truncLen <= 256; - break; - case AUTH_HMAC_SHA384: - isValidLen = keyLen == 384; - isValidTruncLen = truncLen >= 192 && truncLen <= 384; - break; - case AUTH_HMAC_SHA512: - isValidLen = keyLen == 512; - isValidTruncLen = truncLen >= 256 && truncLen <= 512; - break; - case AUTH_AES_XCBC: - isValidLen = keyLen == 128; - isValidTruncLen = truncLen == 96; - break; - case AUTH_AES_CMAC: - isValidLen = keyLen == 128; - isValidTruncLen = truncLen == 96; - break; - case AUTH_CRYPT_AES_GCM: - // The keying material for GCM is a key plus a 32-bit salt - isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; - isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128; - break; - case AUTH_CRYPT_CHACHA20_POLY1305: - // The keying material for ChaCha20Poly1305 is a key plus a 32-bit salt - isValidLen = keyLen == 256 + 32; - isValidTruncLen = truncLen == 128; - break; - default: - // Should never hit here. - throw new IllegalArgumentException("Couldn't find an algorithm: " + name); - } - - if (!isValidLen) { - throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen); - } - if (!isValidTruncLen) { - throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen); - } - } - - /** @hide */ - public boolean isAuthentication() { - switch (getName()) { - // Fallthrough - case AUTH_HMAC_MD5: - case AUTH_HMAC_SHA1: - case AUTH_HMAC_SHA256: - case AUTH_HMAC_SHA384: - case AUTH_HMAC_SHA512: - case AUTH_AES_XCBC: - case AUTH_AES_CMAC: - return true; - default: - return false; - } - } - - /** @hide */ - public boolean isEncryption() { - switch (getName()) { - case CRYPT_AES_CBC: // fallthrough - case CRYPT_AES_CTR: - return true; - default: - return false; - } - } - - /** @hide */ - public boolean isAead() { - switch (getName()) { - case AUTH_CRYPT_AES_GCM: // fallthrough - case AUTH_CRYPT_CHACHA20_POLY1305: - return true; - default: - return false; - } - } - - @Override - @NonNull - public String toString() { - return new StringBuilder() - .append("{mName=") - .append(mName) - .append(", mTruncLenBits=") - .append(mTruncLenBits) - .append("}") - .toString(); - } - - /** @hide */ - @VisibleForTesting - public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) { - if (lhs == null || rhs == null) return (lhs == rhs); - return (lhs.mName.equals(rhs.mName) - && Arrays.equals(lhs.mKey, rhs.mKey) - && lhs.mTruncLenBits == rhs.mTruncLenBits); - } -}; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl deleted file mode 100644 index eaefca74d3a0..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** @hide */ -parcelable IpSecConfig; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java deleted file mode 100644 index 03bb187f119f..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * This class encapsulates all the configuration parameters needed to create IPsec transforms and - * policies. - * - * @hide - */ -public final class IpSecConfig implements Parcelable { - private static final String TAG = "IpSecConfig"; - - // MODE_TRANSPORT or MODE_TUNNEL - private int mMode = IpSecTransform.MODE_TRANSPORT; - - // Preventing this from being null simplifies Java->Native binder - private String mSourceAddress = ""; - - // Preventing this from being null simplifies Java->Native binder - private String mDestinationAddress = ""; - - // The underlying Network that represents the "gateway" Network - // for outbound packets. It may also be used to select packets. - private Network mNetwork; - - // Minimum requirements for identifying a transform - // SPI identifying the IPsec SA in packet processing - // and a destination IP address - private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; - - // Encryption Algorithm - private IpSecAlgorithm mEncryption; - - // Authentication Algorithm - private IpSecAlgorithm mAuthentication; - - // Authenticated Encryption Algorithm - private IpSecAlgorithm mAuthenticatedEncryption; - - // For tunnel mode IPv4 UDP Encapsulation - // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE - private int mEncapType = IpSecTransform.ENCAP_NONE; - private int mEncapSocketResourceId = IpSecManager.INVALID_RESOURCE_ID; - private int mEncapRemotePort; - - // An interval, in seconds between the NattKeepalive packets - private int mNattKeepaliveInterval; - - // XFRM mark and mask; defaults to 0 (no mark/mask) - private int mMarkValue; - private int mMarkMask; - - // XFRM interface id - private int mXfrmInterfaceId; - - /** Set the mode for this IPsec transform */ - public void setMode(int mode) { - mMode = mode; - } - - /** Set the source IP addres for this IPsec transform */ - public void setSourceAddress(String sourceAddress) { - mSourceAddress = sourceAddress; - } - - /** Set the destination IP address for this IPsec transform */ - public void setDestinationAddress(String destinationAddress) { - mDestinationAddress = destinationAddress; - } - - /** Set the SPI by resource ID */ - public void setSpiResourceId(int resourceId) { - mSpiResourceId = resourceId; - } - - /** Set the encryption algorithm */ - public void setEncryption(IpSecAlgorithm encryption) { - mEncryption = encryption; - } - - /** Set the authentication algorithm */ - public void setAuthentication(IpSecAlgorithm authentication) { - mAuthentication = authentication; - } - - /** Set the authenticated encryption algorithm */ - public void setAuthenticatedEncryption(IpSecAlgorithm authenticatedEncryption) { - mAuthenticatedEncryption = authenticatedEncryption; - } - - /** Set the underlying network that will carry traffic for this transform */ - public void setNetwork(Network network) { - mNetwork = network; - } - - public void setEncapType(int encapType) { - mEncapType = encapType; - } - - public void setEncapSocketResourceId(int resourceId) { - mEncapSocketResourceId = resourceId; - } - - public void setEncapRemotePort(int port) { - mEncapRemotePort = port; - } - - public void setNattKeepaliveInterval(int interval) { - mNattKeepaliveInterval = interval; - } - - /** - * Sets the mark value - * - * <p>Internal (System server) use only. Marks passed in by users will be overwritten or - * ignored. - */ - public void setMarkValue(int mark) { - mMarkValue = mark; - } - - /** - * Sets the mark mask - * - * <p>Internal (System server) use only. Marks passed in by users will be overwritten or - * ignored. - */ - public void setMarkMask(int mask) { - mMarkMask = mask; - } - - public void setXfrmInterfaceId(int xfrmInterfaceId) { - mXfrmInterfaceId = xfrmInterfaceId; - } - - // Transport or Tunnel - public int getMode() { - return mMode; - } - - public String getSourceAddress() { - return mSourceAddress; - } - - public int getSpiResourceId() { - return mSpiResourceId; - } - - public String getDestinationAddress() { - return mDestinationAddress; - } - - public IpSecAlgorithm getEncryption() { - return mEncryption; - } - - public IpSecAlgorithm getAuthentication() { - return mAuthentication; - } - - public IpSecAlgorithm getAuthenticatedEncryption() { - return mAuthenticatedEncryption; - } - - public Network getNetwork() { - return mNetwork; - } - - public int getEncapType() { - return mEncapType; - } - - public int getEncapSocketResourceId() { - return mEncapSocketResourceId; - } - - public int getEncapRemotePort() { - return mEncapRemotePort; - } - - public int getNattKeepaliveInterval() { - return mNattKeepaliveInterval; - } - - public int getMarkValue() { - return mMarkValue; - } - - public int getMarkMask() { - return mMarkMask; - } - - public int getXfrmInterfaceId() { - return mXfrmInterfaceId; - } - - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mMode); - out.writeString(mSourceAddress); - out.writeString(mDestinationAddress); - out.writeParcelable(mNetwork, flags); - out.writeInt(mSpiResourceId); - out.writeParcelable(mEncryption, flags); - out.writeParcelable(mAuthentication, flags); - out.writeParcelable(mAuthenticatedEncryption, flags); - out.writeInt(mEncapType); - out.writeInt(mEncapSocketResourceId); - out.writeInt(mEncapRemotePort); - out.writeInt(mNattKeepaliveInterval); - out.writeInt(mMarkValue); - out.writeInt(mMarkMask); - out.writeInt(mXfrmInterfaceId); - } - - @VisibleForTesting - public IpSecConfig() {} - - /** Copy constructor */ - @VisibleForTesting - public IpSecConfig(IpSecConfig c) { - mMode = c.mMode; - mSourceAddress = c.mSourceAddress; - mDestinationAddress = c.mDestinationAddress; - mNetwork = c.mNetwork; - mSpiResourceId = c.mSpiResourceId; - mEncryption = c.mEncryption; - mAuthentication = c.mAuthentication; - mAuthenticatedEncryption = c.mAuthenticatedEncryption; - mEncapType = c.mEncapType; - mEncapSocketResourceId = c.mEncapSocketResourceId; - mEncapRemotePort = c.mEncapRemotePort; - mNattKeepaliveInterval = c.mNattKeepaliveInterval; - mMarkValue = c.mMarkValue; - mMarkMask = c.mMarkMask; - mXfrmInterfaceId = c.mXfrmInterfaceId; - } - - private IpSecConfig(Parcel in) { - mMode = in.readInt(); - mSourceAddress = in.readString(); - mDestinationAddress = in.readString(); - mNetwork = (Network) in.readParcelable(Network.class.getClassLoader(), android.net.Network.class); - mSpiResourceId = in.readInt(); - mEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); - mAuthentication = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); - mAuthenticatedEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); - mEncapType = in.readInt(); - mEncapSocketResourceId = in.readInt(); - mEncapRemotePort = in.readInt(); - mNattKeepaliveInterval = in.readInt(); - mMarkValue = in.readInt(); - mMarkMask = in.readInt(); - mXfrmInterfaceId = in.readInt(); - } - - @Override - public String toString() { - StringBuilder strBuilder = new StringBuilder(); - strBuilder - .append("{mMode=") - .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") - .append(", mSourceAddress=") - .append(mSourceAddress) - .append(", mDestinationAddress=") - .append(mDestinationAddress) - .append(", mNetwork=") - .append(mNetwork) - .append(", mEncapType=") - .append(mEncapType) - .append(", mEncapSocketResourceId=") - .append(mEncapSocketResourceId) - .append(", mEncapRemotePort=") - .append(mEncapRemotePort) - .append(", mNattKeepaliveInterval=") - .append(mNattKeepaliveInterval) - .append("{mSpiResourceId=") - .append(mSpiResourceId) - .append(", mEncryption=") - .append(mEncryption) - .append(", mAuthentication=") - .append(mAuthentication) - .append(", mAuthenticatedEncryption=") - .append(mAuthenticatedEncryption) - .append(", mMarkValue=") - .append(mMarkValue) - .append(", mMarkMask=") - .append(mMarkMask) - .append(", mXfrmInterfaceId=") - .append(mXfrmInterfaceId) - .append("}"); - - return strBuilder.toString(); - } - - public static final @android.annotation.NonNull Parcelable.Creator<IpSecConfig> CREATOR = - new Parcelable.Creator<IpSecConfig>() { - public IpSecConfig createFromParcel(Parcel in) { - return new IpSecConfig(in); - } - - public IpSecConfig[] newArray(int size) { - return new IpSecConfig[size]; - } - }; - - @Override - public boolean equals(@Nullable Object other) { - if (!(other instanceof IpSecConfig)) return false; - final IpSecConfig rhs = (IpSecConfig) other; - return (mMode == rhs.mMode - && mSourceAddress.equals(rhs.mSourceAddress) - && mDestinationAddress.equals(rhs.mDestinationAddress) - && ((mNetwork != null && mNetwork.equals(rhs.mNetwork)) - || (mNetwork == rhs.mNetwork)) - && mEncapType == rhs.mEncapType - && mEncapSocketResourceId == rhs.mEncapSocketResourceId - && mEncapRemotePort == rhs.mEncapRemotePort - && mNattKeepaliveInterval == rhs.mNattKeepaliveInterval - && mSpiResourceId == rhs.mSpiResourceId - && IpSecAlgorithm.equals(mEncryption, rhs.mEncryption) - && IpSecAlgorithm.equals(mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) - && IpSecAlgorithm.equals(mAuthentication, rhs.mAuthentication) - && mMarkValue == rhs.mMarkValue - && mMarkMask == rhs.mMarkMask - && mXfrmInterfaceId == rhs.mXfrmInterfaceId); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java deleted file mode 100644 index 9cb0947b2370..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.RequiresFeature; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.annotation.TestApi; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.ErrnoException; -import android.system.OsConstants; -import android.util.AndroidException; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import dalvik.system.CloseGuard; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.Socket; -import java.util.Objects; - -/** - * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply - * confidentiality (encryption) and integrity (authentication) to IP traffic. - * - * <p>Note that not all aspects of IPsec are permitted by this API. Applications may create - * transport mode security associations and apply them to individual sockets. Applications looking - * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}. - * - * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the - * Internet Protocol</a> - */ -@SystemService(Context.IPSEC_SERVICE) -public class IpSecManager { - private static final String TAG = "IpSecManager"; - - /** - * Used when applying a transform to direct traffic through an {@link IpSecTransform} - * towards the host. - * - * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. - */ - public static final int DIRECTION_IN = 0; - - /** - * Used when applying a transform to direct traffic through an {@link IpSecTransform} - * away from the host. - * - * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. - */ - public static final int DIRECTION_OUT = 1; - - /** - * Used when applying a transform to direct traffic through an {@link IpSecTransform} for - * forwarding between interfaces. - * - * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int DIRECTION_FWD = 2; - - /** @hide */ - @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) - @Retention(RetentionPolicy.SOURCE) - public @interface PolicyDirection {} - - /** - * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. - * - * <p>No IPsec packet may contain an SPI of 0. - * - * @hide - */ - @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; - - /** @hide */ - public interface Status { - int OK = 0; - int RESOURCE_UNAVAILABLE = 1; - int SPI_UNAVAILABLE = 2; - } - - /** @hide */ - public static final int INVALID_RESOURCE_ID = -1; - - /** - * Thrown to indicate that a requested SPI is in use. - * - * <p>The combination of remote {@code InetAddress} and SPI must be unique across all apps on - * one device. If this error is encountered, a new SPI is required before a transform may be - * created. This error can be avoided by calling {@link - * IpSecManager#allocateSecurityParameterIndex}. - */ - public static final class SpiUnavailableException extends AndroidException { - private final int mSpi; - - /** - * Construct an exception indicating that a transform with the given SPI is already in use - * or otherwise unavailable. - * - * @param msg description indicating the colliding SPI - * @param spi the SPI that could not be used due to a collision - */ - SpiUnavailableException(String msg, int spi) { - super(msg + " (spi: " + spi + ")"); - mSpi = spi; - } - - /** Get the SPI that caused a collision. */ - public int getSpi() { - return mSpi; - } - } - - /** - * Thrown to indicate that an IPsec resource is unavailable. - * - * <p>This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link - * IpSecTransform}, or other system resources. If this exception is thrown, users should release - * allocated objects of the type requested. - */ - public static final class ResourceUnavailableException extends AndroidException { - - ResourceUnavailableException(String msg) { - super(msg); - } - } - - private final Context mContext; - private final IIpSecService mService; - - /** - * This class represents a reserved SPI. - * - * <p>Objects of this type are used to track reserved security parameter indices. They can be - * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released - * by calling {@link #close()} when they are no longer needed. - */ - public static final class SecurityParameterIndex implements AutoCloseable { - private final IIpSecService mService; - private final InetAddress mDestinationAddress; - private final CloseGuard mCloseGuard = CloseGuard.get(); - private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; - private int mResourceId = INVALID_RESOURCE_ID; - - /** Get the underlying SPI held by this object. */ - public int getSpi() { - return mSpi; - } - - /** - * Release an SPI that was previously reserved. - * - * <p>Release an SPI for use by other users in the system. If a SecurityParameterIndex is - * applied to an IpSecTransform, it will become unusable for future transforms but should - * still be closed to ensure system resources are released. - */ - @Override - public void close() { - try { - mService.releaseSecurityParameterIndex(mResourceId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - } - - /** Check that the SPI was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - - close(); - } - - private SecurityParameterIndex( - @NonNull IIpSecService service, InetAddress destinationAddress, int spi) - throws ResourceUnavailableException, SpiUnavailableException { - mService = service; - mDestinationAddress = destinationAddress; - try { - IpSecSpiResponse result = - mService.allocateSecurityParameterIndex( - destinationAddress.getHostAddress(), spi, new Binder()); - - if (result == null) { - throw new NullPointerException("Received null response from IpSecService"); - } - - int status = result.status; - switch (status) { - case Status.OK: - break; - case Status.RESOURCE_UNAVAILABLE: - throw new ResourceUnavailableException( - "No more SPIs may be allocated by this requester."); - case Status.SPI_UNAVAILABLE: - throw new SpiUnavailableException("Requested SPI is unavailable", spi); - default: - throw new RuntimeException( - "Unknown status returned by IpSecService: " + status); - } - mSpi = result.spi; - mResourceId = result.resourceId; - - if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { - throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); - } - - if (mResourceId == INVALID_RESOURCE_ID) { - throw new RuntimeException( - "Invalid Resource ID returned by IpSecService: " + status); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - mCloseGuard.open("open"); - } - - /** @hide */ - @VisibleForTesting - public int getResourceId() { - return mResourceId; - } - - @Override - public String toString() { - return new StringBuilder() - .append("SecurityParameterIndex{spi=") - .append(mSpi) - .append(",resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } - } - - /** - * Reserve a random SPI for traffic bound to or from the specified destination address. - * - * <p>If successful, this SPI is guaranteed available until released by a call to {@link - * SecurityParameterIndex#close()}. - * - * @param destinationAddress the destination address for traffic bearing the requested SPI. - * For inbound traffic, the destination should be an address currently assigned on-device. - * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are - * currently allocated for this user - */ - @NonNull - public SecurityParameterIndex allocateSecurityParameterIndex( - @NonNull InetAddress destinationAddress) throws ResourceUnavailableException { - try { - return new SecurityParameterIndex( - mService, - destinationAddress, - IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); - } catch (ServiceSpecificException e) { - throw rethrowUncheckedExceptionFromServiceSpecificException(e); - } catch (SpiUnavailableException unlikely) { - // Because this function allocates a totally random SPI, it really shouldn't ever - // fail to allocate an SPI; we simply need this because the exception is checked. - throw new ResourceUnavailableException("No SPIs available"); - } - } - - /** - * Reserve the requested SPI for traffic bound to or from the specified destination address. - * - * <p>If successful, this SPI is guaranteed available until released by a call to {@link - * SecurityParameterIndex#close()}. - * - * @param destinationAddress the destination address for traffic bearing the requested SPI. - * For inbound traffic, the destination should be an address currently assigned on-device. - * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See - * RFC 4303 Section 2.1. - * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are - * currently allocated for this user - * @throws SpiUnavailableException indicating that the requested SPI could not be - * reserved - */ - @NonNull - public SecurityParameterIndex allocateSecurityParameterIndex( - @NonNull InetAddress destinationAddress, int requestedSpi) - throws SpiUnavailableException, ResourceUnavailableException { - if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { - throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); - } - try { - return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); - } catch (ServiceSpecificException e) { - throw rethrowUncheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * Apply an IPsec transform to a stream socket. - * - * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the - * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, - * unprotected traffic can resume on that socket. - * - * <p>For security reasons, the destination address of any traffic on the socket must match the - * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any - * other IP address will result in an IOException. In addition, reads and writes on the socket - * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. - * - * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an - * applied transform before completion of graceful shutdown may result in the shutdown sequence - * failing to complete. As such, applications requiring graceful shutdown MUST close the socket - * prior to deactivating the applied transform. Socket closure may be performed asynchronously - * (in batches), so the returning of a close function does not guarantee shutdown of a socket. - * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is - * sufficient to ensure shutdown. - * - * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), - * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] - * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the - * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. - * - * <h4>Rekey Procedure</h4> - * - * <p>When applying a new tranform to a socket in the outbound direction, the previous transform - * will be removed and the new transform will take effect immediately, sending all traffic on - * the new transform; however, when applying a transform in the inbound direction, traffic - * on the old transform will continue to be decrypted and delivered until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey - * procedures where both transforms are valid until both endpoints are using the new transform - * and all in-flight packets have been received. - * - * @param socket a stream socket - * @param direction the direction in which the transform should be applied - * @param transform a transport mode {@code IpSecTransform} - * @throws IOException indicating that the transform could not be applied - */ - public void applyTransportModeTransform(@NonNull Socket socket, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - // Ensure creation of FD. See b/77548890 for more details. - socket.getSoLinger(); - - applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); - } - - /** - * Apply an IPsec transform to a datagram socket. - * - * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the - * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, - * unprotected traffic can resume on that socket. - * - * <p>For security reasons, the destination address of any traffic on the socket must match the - * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any - * other IP address will result in an IOException. In addition, reads and writes on the socket - * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. - * - * <h4>Rekey Procedure</h4> - * - * <p>When applying a new tranform to a socket in the outbound direction, the previous transform - * will be removed and the new transform will take effect immediately, sending all traffic on - * the new transform; however, when applying a transform in the inbound direction, traffic - * on the old transform will continue to be decrypted and delivered until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey - * procedures where both transforms are valid until both endpoints are using the new transform - * and all in-flight packets have been received. - * - * @param socket a datagram socket - * @param direction the direction in which the transform should be applied - * @param transform a transport mode {@code IpSecTransform} - * @throws IOException indicating that the transform could not be applied - */ - public void applyTransportModeTransform(@NonNull DatagramSocket socket, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); - } - - /** - * Apply an IPsec transform to a socket. - * - * <p>This applies transport mode encapsulation to the given socket. Once applied, I/O on the - * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, - * unprotected traffic can resume on that socket. - * - * <p>For security reasons, the destination address of any traffic on the socket must match the - * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any - * other IP address will result in an IOException. In addition, reads and writes on the socket - * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. - * - * <p>Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an - * applied transform before completion of graceful shutdown may result in the shutdown sequence - * failing to complete. As such, applications requiring graceful shutdown MUST close the socket - * prior to deactivating the applied transform. Socket closure may be performed asynchronously - * (in batches), so the returning of a close function does not guarantee shutdown of a socket. - * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is - * sufficient to ensure shutdown. - * - * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), - * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] - * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the - * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. - * - * <h4>Rekey Procedure</h4> - * - * <p>When applying a new tranform to a socket in the outbound direction, the previous transform - * will be removed and the new transform will take effect immediately, sending all traffic on - * the new transform; however, when applying a transform in the inbound direction, traffic - * on the old transform will continue to be decrypted and delivered until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey - * procedures where both transforms are valid until both endpoints are using the new transform - * and all in-flight packets have been received. - * - * @param socket a socket file descriptor - * @param direction the direction in which the transform should be applied - * @param transform a transport mode {@code IpSecTransform} - * @throws IOException indicating that the transform could not be applied - */ - public void applyTransportModeTransform(@NonNull FileDescriptor socket, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() - // constructor takes control and closes the user's FD when we exit the method. - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove an IPsec transform from a stream socket. - * - * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a - * socket allows the socket to be reused for communication in the clear. - * - * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling - * {@link IpSecTransform#close()}, then communication on the socket will fail until this method - * is called. - * - * @param socket a socket that previously had a transform applied to it - * @throws IOException indicating that the transform could not be removed from the socket - */ - public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException { - // Ensure creation of FD. See b/77548890 for more details. - socket.getSoLinger(); - - removeTransportModeTransforms(socket.getFileDescriptor$()); - } - - /** - * Remove an IPsec transform from a datagram socket. - * - * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a - * socket allows the socket to be reused for communication in the clear. - * - * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling - * {@link IpSecTransform#close()}, then communication on the socket will fail until this method - * is called. - * - * @param socket a socket that previously had a transform applied to it - * @throws IOException indicating that the transform could not be removed from the socket - */ - public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException { - removeTransportModeTransforms(socket.getFileDescriptor$()); - } - - /** - * Remove an IPsec transform from a socket. - * - * <p>Once removed, traffic on the socket will not be encrypted. Removing transforms from a - * socket allows the socket to be reused for communication in the clear. - * - * <p>If an {@code IpSecTransform} object applied to this socket was deallocated by calling - * {@link IpSecTransform#close()}, then communication on the socket will fail until this method - * is called. - * - * @param socket a socket that previously had a transform applied to it - * @throws IOException indicating that the transform could not be removed from the socket - */ - public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - mService.removeTransportModeTransforms(pfd); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of - * cleanup if a tunneled Network experiences a change in default route. The Network will drop - * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is - * lost, all traffic will drop. - * - * <p>TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. - * - * @param net a network that currently has transform applied to it. - * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given - * network - * @hide - */ - public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} - - /** - * This class provides access to a UDP encapsulation Socket. - * - * <p>{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2 - * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link - * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the - * caller. The caller should not close the {@code FileDescriptor} returned by {@link - * #getFileDescriptor}, but should use {@link #close} instead. - * - * <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic - * of the next user who binds to that port. To prevent this scenario, these sockets are held - * open by the system so that they may only be closed by calling {@link #close} or when the user - * process exits. - */ - public static final class UdpEncapsulationSocket implements AutoCloseable { - private final ParcelFileDescriptor mPfd; - private final IIpSecService mService; - private int mResourceId = INVALID_RESOURCE_ID; - private final int mPort; - private final CloseGuard mCloseGuard = CloseGuard.get(); - - private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) - throws ResourceUnavailableException, IOException { - mService = service; - try { - IpSecUdpEncapResponse result = - mService.openUdpEncapsulationSocket(port, new Binder()); - switch (result.status) { - case Status.OK: - break; - case Status.RESOURCE_UNAVAILABLE: - throw new ResourceUnavailableException( - "No more Sockets may be allocated by this requester."); - default: - throw new RuntimeException( - "Unknown status returned by IpSecService: " + result.status); - } - mResourceId = result.resourceId; - mPort = result.port; - mPfd = result.fileDescriptor; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - mCloseGuard.open("constructor"); - } - - /** Get the encapsulation socket's file descriptor. */ - public FileDescriptor getFileDescriptor() { - if (mPfd == null) { - return null; - } - return mPfd.getFileDescriptor(); - } - - /** Get the bound port of the wrapped socket. */ - public int getPort() { - return mPort; - } - - /** - * Close this socket. - * - * <p>This closes the wrapped socket. Open encapsulation sockets count against a user's - * resource limits, and forgetting to close them eventually will result in {@link - * ResourceUnavailableException} being thrown. - */ - @Override - public void close() throws IOException { - try { - mService.closeUdpEncapsulationSocket(mResourceId); - mResourceId = INVALID_RESOURCE_ID; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - - try { - mPfd.close(); - } catch (IOException e) { - Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); - throw e; - } - } - - /** Check that the socket was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /** @hide */ - @SystemApi(client = MODULE_LIBRARIES) - public int getResourceId() { - return mResourceId; - } - - @Override - public String toString() { - return new StringBuilder() - .append("UdpEncapsulationSocket{port=") - .append(mPort) - .append(",resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } - }; - - /** - * Open a socket for UDP encapsulation and bind to the given port. - * - * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. - * - * @param port a local UDP port - * @return a socket that is bound to the given port - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open - */ - // Returning a socket in this fashion that has been created and bound by the system - // is the only safe way to ensure that a socket is both accessible to the user and - // safely usable for Encapsulation without allowing a user to possibly unbind from/close - // the port, which could potentially impact the traffic of the next user who binds to that - // socket. - @NonNull - public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) - throws IOException, ResourceUnavailableException { - /* - * Most range checking is done in the service, but this version of the constructor expects - * a valid port number, and zero cannot be checked after being passed to the service. - */ - if (port == 0) { - throw new IllegalArgumentException("Specified port must be a valid port number!"); - } - try { - return new UdpEncapsulationSocket(mService, port); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * Open a socket for UDP encapsulation. - * - * <p>See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. - * - * <p>The local port of the returned socket can be obtained by calling {@link - * UdpEncapsulationSocket#getPort()}. - * - * @return a socket that is bound to a local port - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open - */ - // Returning a socket in this fashion that has been created and bound by the system - // is the only safe way to ensure that a socket is both accessible to the user and - // safely usable for Encapsulation without allowing a user to possibly unbind from/close - // the port, which could potentially impact the traffic of the next user who binds to that - // socket. - @NonNull - public UdpEncapsulationSocket openUdpEncapsulationSocket() - throws IOException, ResourceUnavailableException { - try { - return new UdpEncapsulationSocket(mService, 0); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * This class represents an IpSecTunnelInterface - * - * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as - * local endpoints for IPsec tunnels. - * - * <p>Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be - * applied to provide IPsec security to packets sent through the tunnel. While a tunnel - * cannot be used in standalone mode within Android, the higher layers may use the tunnel - * to create Network objects which are accessible to the Android system. - * @hide - */ - @SystemApi - public static final class IpSecTunnelInterface implements AutoCloseable { - private final String mOpPackageName; - private final IIpSecService mService; - private final InetAddress mRemoteAddress; - private final InetAddress mLocalAddress; - private final Network mUnderlyingNetwork; - private final CloseGuard mCloseGuard = CloseGuard.get(); - private String mInterfaceName; - private int mResourceId = INVALID_RESOURCE_ID; - - /** Get the underlying SPI held by this object. */ - @NonNull - public String getInterfaceName() { - return mInterfaceName; - } - - /** - * Add an address to the IpSecTunnelInterface - * - * <p>Add an address which may be used as the local inner address for - * tunneled traffic. - * - * @param address the local address for traffic inside the tunnel - * @param prefixLen length of the InetAddress prefix - * @hide - */ - @SystemApi - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { - try { - mService.addAddressToTunnelInterface( - mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove an address from the IpSecTunnelInterface - * - * <p>Remove an address which was previously added to the IpSecTunnelInterface - * - * @param address to be removed - * @param prefixLen length of the InetAddress prefix - * @hide - */ - @SystemApi - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { - try { - mService.removeAddressFromTunnelInterface( - mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Update the underlying network for this IpSecTunnelInterface. - * - * <p>This new underlying network will be used for all transforms applied AFTER this call is - * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to - * this tunnel interface, traffic will still use the old SA, and be routed on the old - * underlying network. - * - * <p>To migrate IPsec tunnel mode traffic, a caller should: - * - * <ol> - * <li>Update the IpSecTunnelInterface’s underlying network. - * <li>Apply {@link IpSecTransform}(s) with matching addresses to this - * IpSecTunnelInterface. - * </ol> - * - * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel. - * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise - * this method will throw an {@link IllegalArgumentException}. If the - * IpSecTunnelInterface is later added to this network, all outbound traffic will be - * blackholed. - */ - // TODO: b/169171001 Update the documentation when transform migration is supported. - // The purpose of making updating network and applying transforms separate is to leave open - // the possibility to support lossless migration procedures. To do that, Android platform - // will need to support multiple inbound tunnel mode transforms, just like it can support - // multiple transport mode transforms. - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException { - try { - mService.setNetworkForTunnelInterface( - mResourceId, underlyingNetwork, mOpPackageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service, - @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, - @NonNull Network underlyingNetwork) - throws ResourceUnavailableException, IOException { - mOpPackageName = ctx.getOpPackageName(); - mService = service; - mLocalAddress = localAddress; - mRemoteAddress = remoteAddress; - mUnderlyingNetwork = underlyingNetwork; - - try { - IpSecTunnelInterfaceResponse result = - mService.createTunnelInterface( - localAddress.getHostAddress(), - remoteAddress.getHostAddress(), - underlyingNetwork, - new Binder(), - mOpPackageName); - switch (result.status) { - case Status.OK: - break; - case Status.RESOURCE_UNAVAILABLE: - throw new ResourceUnavailableException( - "No more tunnel interfaces may be allocated by this requester."); - default: - throw new RuntimeException( - "Unknown status returned by IpSecService: " + result.status); - } - mResourceId = result.resourceId; - mInterfaceName = result.interfaceName; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - mCloseGuard.open("constructor"); - } - - /** - * Delete an IpSecTunnelInterface - * - * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system - * resources. Any packets bound for this interface either inbound or outbound will - * all be lost. - */ - @Override - public void close() { - try { - mService.deleteTunnelInterface(mResourceId, mOpPackageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - } - - /** Check that the Interface was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /** @hide */ - @VisibleForTesting - public int getResourceId() { - return mResourceId; - } - - @NonNull - @Override - public String toString() { - return new StringBuilder() - .append("IpSecTunnelInterface{ifname=") - .append(mInterfaceName) - .append(",resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } - } - - /** - * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. - * - * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the - * underlying network goes away, and the onLost() callback is received. - * - * @param localAddress The local addres of the tunnel - * @param remoteAddress The local addres of the tunnel - * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. - * This network should almost certainly be a network such as WiFi with an L2 address. - * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open - * @hide - */ - @SystemApi - @NonNull - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, - @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) - throws ResourceUnavailableException, IOException { - try { - return new IpSecTunnelInterface( - mContext, mService, localAddress, remoteAddress, underlyingNetwork); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will - * tunnel all traffic for the given direction through the underlying network's interface with - * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional - * IP header and IPsec Header on all inbound traffic). - * <p>Applications should probably not use this API directly. - * - * - * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied - * transform. - * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which - * the transform will be used. - * @param transform an {@link IpSecTransform} created in tunnel mode - * @throws IOException indicating that the transform could not be applied due to a lower - * layer failure. - * @hide - */ - @SystemApi - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - try { - mService.applyTunnelModeTransform( - tunnel.getResourceId(), direction, - transform.getResourceId(), mContext.getOpPackageName()); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - */ - public IpSecTransformResponse createTransform(IpSecConfig config, IBinder binder, - String callingPackage) { - try { - return mService.createTransform(config, binder, callingPackage); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - */ - public void deleteTransform(int resourceId) { - try { - mService.deleteTransform(resourceId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Construct an instance of IpSecManager within an application context. - * - * @param context the application context for this manager - * @hide - */ - public IpSecManager(Context ctx, IIpSecService service) { - mContext = ctx; - mService = Objects.requireNonNull(service, "missing service"); - } - - private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) { - // OsConstants are late binding, so switch statements can't be used. - if (sse.errorCode == OsConstants.EINVAL) { - throw new IllegalArgumentException(sse); - } else if (sse.errorCode == OsConstants.EAGAIN) { - throw new IllegalStateException(sse); - } else if (sse.errorCode == OsConstants.EOPNOTSUPP - || sse.errorCode == OsConstants.EPROTONOSUPPORT) { - throw new UnsupportedOperationException(sse); - } - } - - /** - * Convert an Errno SSE to the correct Unchecked exception type. - * - * This method never actually returns. - */ - // package - static RuntimeException - rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) { - maybeHandleServiceSpecificException(sse); - throw new RuntimeException(sse); - } - - /** - * Convert an Errno SSE to the correct Checked or Unchecked exception type. - * - * This method may throw IOException, or it may throw an unchecked exception; it will never - * actually return. - */ - // package - static IOException rethrowCheckedExceptionFromServiceSpecificException( - ServiceSpecificException sse) throws IOException { - // First see if this is an unchecked exception of a type we know. - // If so, then we prefer the unchecked (specific) type of exception. - maybeHandleServiceSpecificException(sse); - // If not, then all we can do is provide the SSE in the form of an IOException. - throw new ErrnoException( - "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException(); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl deleted file mode 100644 index 6484a0013c53..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** @hide */ -parcelable IpSecSpiResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java deleted file mode 100644 index f99e570fb761..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class is used to return an SPI and corresponding status from the IpSecService to an - * IpSecManager.SecurityParameterIndex. - * - * @hide - */ -public final class IpSecSpiResponse implements Parcelable { - private static final String TAG = "IpSecSpiResponse"; - - public final int resourceId; - public final int status; - public final int spi; - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - out.writeInt(spi); - } - - public IpSecSpiResponse(int inStatus, int inResourceId, int inSpi) { - status = inStatus; - resourceId = inResourceId; - spi = inSpi; - } - - public IpSecSpiResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - } - - private IpSecSpiResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - spi = in.readInt(); - } - - public static final @android.annotation.NonNull Parcelable.Creator<IpSecSpiResponse> CREATOR = - new Parcelable.Creator<IpSecSpiResponse>() { - public IpSecSpiResponse createFromParcel(Parcel in) { - return new IpSecSpiResponse(in); - } - - public IpSecSpiResponse[] newArray(int size) { - return new IpSecSpiResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java deleted file mode 100644 index 68ae5de4ee70..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import static android.net.IpSecManager.INVALID_RESOURCE_ID; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresFeature; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.ServiceSpecificException; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import dalvik.system.CloseGuard; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.InetAddress; -import java.util.Objects; - -/** - * This class represents a transform, which roughly corresponds to an IPsec Security Association. - * - * <p>Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform} - * object encapsulates the properties and state of an IPsec security association. That includes, - * but is not limited to, algorithm choice, key material, and allocated system resources. - * - * @see <a href="https://tools.ietf.org/html/rfc4301">RFC 4301, Security Architecture for the - * Internet Protocol</a> - */ -public final class IpSecTransform implements AutoCloseable { - private static final String TAG = "IpSecTransform"; - - /** @hide */ - public static final int MODE_TRANSPORT = 0; - - /** @hide */ - public static final int MODE_TUNNEL = 1; - - /** @hide */ - public static final int ENCAP_NONE = 0; - - /** - * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP - * header and payload. This prevents traffic from being interpreted as ESP or IKEv2. - * - * @hide - */ - public static final int ENCAP_ESPINUDP_NON_IKE = 1; - - /** - * IPsec traffic will be encapsulated within UDP as per - * <a href="https://tools.ietf.org/html/rfc3948">RFC 3498</a>. - * - * @hide - */ - public static final int ENCAP_ESPINUDP = 2; - - /** @hide */ - @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NON_IKE}) - @Retention(RetentionPolicy.SOURCE) - public @interface EncapType {} - - /** @hide */ - @VisibleForTesting - public IpSecTransform(Context context, IpSecConfig config) { - mContext = context; - mConfig = new IpSecConfig(config); - mResourceId = INVALID_RESOURCE_ID; - } - - private IpSecManager getIpSecManager(Context context) { - return context.getSystemService(IpSecManager.class); - } - /** - * Checks the result status and throws an appropriate exception if the status is not Status.OK. - */ - private void checkResultStatus(int status) - throws IOException, IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException { - switch (status) { - case IpSecManager.Status.OK: - return; - // TODO: Pass Error string back from bundle so that errors can be more specific - case IpSecManager.Status.RESOURCE_UNAVAILABLE: - throw new IpSecManager.ResourceUnavailableException( - "Failed to allocate a new IpSecTransform"); - case IpSecManager.Status.SPI_UNAVAILABLE: - Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved"); - // Fall through - default: - throw new IllegalStateException( - "Failed to Create a Transform with status code " + status); - } - } - - private IpSecTransform activate() - throws IOException, IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException { - synchronized (this) { - try { - IpSecTransformResponse result = getIpSecManager(mContext).createTransform( - mConfig, new Binder(), mContext.getOpPackageName()); - int status = result.status; - checkResultStatus(status); - mResourceId = result.resourceId; - Log.d(TAG, "Added Transform with Id " + mResourceId); - mCloseGuard.open("build"); - } catch (ServiceSpecificException e) { - throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e); - } - } - - return this; - } - - /** - * Standard equals. - */ - public boolean equals(@Nullable Object other) { - if (this == other) return true; - if (!(other instanceof IpSecTransform)) return false; - final IpSecTransform rhs = (IpSecTransform) other; - return getConfig().equals(rhs.getConfig()) && mResourceId == rhs.mResourceId; - } - - /** - * Deactivate this {@code IpSecTransform} and free allocated resources. - * - * <p>Deactivating a transform while it is still applied to a socket will result in errors on - * that socket. Make sure to remove transforms by calling {@link - * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a - * socket will not deactivate it (because one transform may be applied to multiple sockets). - * - * <p>It is safe to call this method on a transform that has already been deactivated. - */ - public void close() { - Log.d(TAG, "Removing Transform with Id " + mResourceId); - - // Always safe to attempt cleanup - if (mResourceId == INVALID_RESOURCE_ID) { - mCloseGuard.close(); - return; - } - try { - getIpSecManager(mContext).deleteTransform(mResourceId); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - } - - /** Check that the transform was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /* Package */ - IpSecConfig getConfig() { - return mConfig; - } - - private final IpSecConfig mConfig; - private int mResourceId; - private final Context mContext; - private final CloseGuard mCloseGuard = CloseGuard.get(); - - /** @hide */ - @VisibleForTesting - public int getResourceId() { - return mResourceId; - } - - /** - * A callback class to provide status information regarding a NAT-T keepalive session - * - * <p>Use this callback to receive status information regarding a NAT-T keepalive session - * by registering it when calling {@link #startNattKeepalive}. - * - * @hide - */ - public static class NattKeepaliveCallback { - /** The specified {@code Network} is not connected. */ - public static final int ERROR_INVALID_NETWORK = 1; - /** The hardware does not support this request. */ - public static final int ERROR_HARDWARE_UNSUPPORTED = 2; - /** The hardware returned an error. */ - public static final int ERROR_HARDWARE_ERROR = 3; - - /** The requested keepalive was successfully started. */ - public void onStarted() {} - /** The keepalive was successfully stopped. */ - public void onStopped() {} - /** An error occurred. */ - public void onError(int error) {} - } - - /** This class is used to build {@link IpSecTransform} objects. */ - public static class Builder { - private Context mContext; - private IpSecConfig mConfig; - - /** - * Set the encryption algorithm. - * - * <p>Encryption is mutually exclusive with authenticated encryption. - * - * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. - */ - @NonNull - public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { - // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. - Objects.requireNonNull(algo); - mConfig.setEncryption(algo); - return this; - } - - /** - * Set the authentication (integrity) algorithm. - * - * <p>Authentication is mutually exclusive with authenticated encryption. - * - * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. - */ - @NonNull - public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { - // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. - Objects.requireNonNull(algo); - mConfig.setAuthentication(algo); - return this; - } - - /** - * Set the authenticated encryption algorithm. - * - * <p>The Authenticated Encryption (AE) class of algorithms are also known as - * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode - * algorithms (as referred to in - * <a href="https://tools.ietf.org/html/rfc4301">RFC 4301</a>). - * - * <p>Authenticated encryption is mutually exclusive with encryption and authentication. - * - * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to - * be applied. - */ - @NonNull - public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { - Objects.requireNonNull(algo); - mConfig.setAuthenticatedEncryption(algo); - return this; - } - - /** - * Add UDP encapsulation to an IPv4 transform. - * - * <p>This allows IPsec traffic to pass through a NAT. - * - * @see <a href="https://tools.ietf.org/html/rfc3948">RFC 3948, UDP Encapsulation of IPsec - * ESP Packets</a> - * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.23">RFC 7296 section 2.23, - * NAT Traversal of IKEv2</a> - * @param localSocket a socket for sending and receiving encapsulated traffic - * @param remotePort the UDP port number of the remote host that will send and receive - * encapsulated traffic. In the case of IKEv2, this should be port 4500. - */ - @NonNull - public IpSecTransform.Builder setIpv4Encapsulation( - @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { - Objects.requireNonNull(localSocket); - mConfig.setEncapType(ENCAP_ESPINUDP); - if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); - } - mConfig.setEncapSocketResourceId(localSocket.getResourceId()); - mConfig.setEncapRemotePort(remotePort); - return this; - } - - /** - * Build a transport mode {@link IpSecTransform}. - * - * <p>This builds and activates a transport mode transform. Note that an active transform - * will not affect any network traffic until it has been applied to one or more sockets. - * - * @see IpSecManager#applyTransportModeTransform - * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use - * this transform; this address must belong to the Network used by all sockets that - * utilize this transform; if provided, then only traffic originating from the - * specified source address will be processed. - * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed - * traffic - * @throws IllegalArgumentException indicating that a particular combination of transform - * properties is invalid - * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms - * are active - * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI - * collides with an existing transform - * @throws IOException indicating other errors - */ - @NonNull - public IpSecTransform buildTransportModeTransform( - @NonNull InetAddress sourceAddress, - @NonNull IpSecManager.SecurityParameterIndex spi) - throws IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException, IOException { - Objects.requireNonNull(sourceAddress); - Objects.requireNonNull(spi); - if (spi.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid SecurityParameterIndex"); - } - mConfig.setMode(MODE_TRANSPORT); - mConfig.setSourceAddress(sourceAddress.getHostAddress()); - mConfig.setSpiResourceId(spi.getResourceId()); - // FIXME: modifying a builder after calling build can change the built transform. - return new IpSecTransform(mContext, mConfig).activate(); - } - - /** - * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some - * parameters have interdependencies that are checked at build time. - * - * @param sourceAddress the {@link InetAddress} that provides the source address for this - * IPsec tunnel. This is almost certainly an address belonging to the {@link Network} - * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}. - * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed - * traffic - * @throws IllegalArgumentException indicating that a particular combination of transform - * properties is invalid. - * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms - * are active - * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI - * collides with an existing transform - * @throws IOException indicating other errors - * @hide - */ - @SystemApi - @NonNull - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public IpSecTransform buildTunnelModeTransform( - @NonNull InetAddress sourceAddress, - @NonNull IpSecManager.SecurityParameterIndex spi) - throws IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException, IOException { - Objects.requireNonNull(sourceAddress); - Objects.requireNonNull(spi); - if (spi.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid SecurityParameterIndex"); - } - mConfig.setMode(MODE_TUNNEL); - mConfig.setSourceAddress(sourceAddress.getHostAddress()); - mConfig.setSpiResourceId(spi.getResourceId()); - return new IpSecTransform(mContext, mConfig).activate(); - } - - /** - * Create a new IpSecTransform.Builder. - * - * @param context current context - */ - public Builder(@NonNull Context context) { - Objects.requireNonNull(context); - mContext = context; - mConfig = new IpSecConfig(); - } - } - - @Override - public String toString() { - return new StringBuilder() - .append("IpSecTransform{resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl deleted file mode 100644 index 546230d5b888..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** @hide */ -parcelable IpSecTransformResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java deleted file mode 100644 index 363f3165ee65..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class is used to return an IpSecTransform resource Id and and corresponding status from the - * IpSecService to an IpSecTransform object. - * - * @hide - */ -public final class IpSecTransformResponse implements Parcelable { - private static final String TAG = "IpSecTransformResponse"; - - public final int resourceId; - public final int status; - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - } - - public IpSecTransformResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - } - - public IpSecTransformResponse(int inStatus, int inResourceId) { - status = inStatus; - resourceId = inResourceId; - } - - private IpSecTransformResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - } - - @android.annotation.NonNull - public static final Parcelable.Creator<IpSecTransformResponse> CREATOR = - new Parcelable.Creator<IpSecTransformResponse>() { - public IpSecTransformResponse createFromParcel(Parcel in) { - return new IpSecTransformResponse(in); - } - - public IpSecTransformResponse[] newArray(int size) { - return new IpSecTransformResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl deleted file mode 100644 index 7239221415ce..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -/** @hide */ -parcelable IpSecTunnelInterfaceResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java deleted file mode 100644 index 127e30a69394..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class is used to return an IpSecTunnelInterface resource Id and and corresponding status - * from the IpSecService to an IpSecTunnelInterface object. - * - * @hide - */ -public final class IpSecTunnelInterfaceResponse implements Parcelable { - private static final String TAG = "IpSecTunnelInterfaceResponse"; - - public final int resourceId; - public final String interfaceName; - public final int status; - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - out.writeString(interfaceName); - } - - public IpSecTunnelInterfaceResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - interfaceName = ""; - } - - public IpSecTunnelInterfaceResponse(int inStatus, int inResourceId, String inInterfaceName) { - status = inStatus; - resourceId = inResourceId; - interfaceName = inInterfaceName; - } - - private IpSecTunnelInterfaceResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - interfaceName = in.readString(); - } - - @android.annotation.NonNull - public static final Parcelable.Creator<IpSecTunnelInterfaceResponse> CREATOR = - new Parcelable.Creator<IpSecTunnelInterfaceResponse>() { - public IpSecTunnelInterfaceResponse createFromParcel(Parcel in) { - return new IpSecTunnelInterfaceResponse(in); - } - - public IpSecTunnelInterfaceResponse[] newArray(int size) { - return new IpSecTunnelInterfaceResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl deleted file mode 100644 index 5e451f3651f1..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** @hide */ -parcelable IpSecUdpEncapResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java deleted file mode 100644 index 390af8236696..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.Parcelable; - -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * This class is used to return a UDP Socket and corresponding status from the IpSecService to an - * IpSecManager.UdpEncapsulationSocket. - * - * @hide - */ -public final class IpSecUdpEncapResponse implements Parcelable { - private static final String TAG = "IpSecUdpEncapResponse"; - - public final int resourceId; - public final int port; - public final int status; - // There is a weird asymmetry with FileDescriptor: you can write a FileDescriptor - // but you read a ParcelFileDescriptor. To circumvent this, when we receive a FD - // from the user, we immediately create a ParcelFileDescriptor DUP, which we invalidate - // on writeParcel() by setting the flag to do close-on-write. - // TODO: tests to ensure this doesn't leak - public final ParcelFileDescriptor fileDescriptor; - - // Parcelable Methods - - @Override - public int describeContents() { - return (fileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - out.writeInt(port); - out.writeParcelable(fileDescriptor, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); - } - - public IpSecUdpEncapResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - port = -1; - fileDescriptor = null; // yes I know it's redundant, but readability - } - - public IpSecUdpEncapResponse(int inStatus, int inResourceId, int inPort, FileDescriptor inFd) - throws IOException { - if (inStatus == IpSecManager.Status.OK && inFd == null) { - throw new IllegalArgumentException("Valid status implies FD must be non-null"); - } - status = inStatus; - resourceId = inResourceId; - port = inPort; - fileDescriptor = (status == IpSecManager.Status.OK) ? ParcelFileDescriptor.dup(inFd) : null; - } - - private IpSecUdpEncapResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - port = in.readInt(); - fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class); - } - - @android.annotation.NonNull - public static final Parcelable.Creator<IpSecUdpEncapResponse> CREATOR = - new Parcelable.Creator<IpSecUdpEncapResponse>() { - public IpSecUdpEncapResponse createFromParcel(Parcel in) { - return new IpSecUdpEncapResponse(in); - } - - public IpSecUdpEncapResponse[] newArray(int size) { - return new IpSecUdpEncapResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java deleted file mode 100644 index da5f88dc3b7e..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.app.usage.NetworkStatsManager; -import android.content.Context; -import android.net.wifi.WifiInfo; -import android.service.NetworkIdentityProto; -import android.telephony.TelephonyManager; -import android.util.proto.ProtoOutputStream; - -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkCapabilitiesUtils; -import com.android.net.module.util.NetworkIdentityUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Objects; - -/** - * Network definition that includes strong identity. Analogous to combining - * {@link NetworkCapabilities} and an IMSI. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public class NetworkIdentity { - private static final String TAG = "NetworkIdentity"; - - /** @hide */ - // TODO: Remove this after migrating all callers to use - // {@link NetworkTemplate#NETWORK_TYPE_ALL} instead. - public static final int SUBTYPE_COMBINED = -1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "OEM_MANAGED_" }, flag = true, value = { - NetworkTemplate.OEM_MANAGED_NO, - NetworkTemplate.OEM_MANAGED_PAID, - NetworkTemplate.OEM_MANAGED_PRIVATE - }) - public @interface OemManaged{} - - /** - * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}. - * @hide - */ - public static final int OEM_NONE = 0x0; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. - * @hide - */ - public static final int OEM_PAID = 1 << 0; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. - * @hide - */ - public static final int OEM_PRIVATE = 1 << 1; - - private static final long SUPPORTED_OEM_MANAGED_TYPES = OEM_PAID | OEM_PRIVATE; - - final int mType; - final int mRatType; - final int mSubId; - final String mSubscriberId; - final String mWifiNetworkKey; - final boolean mRoaming; - final boolean mMetered; - final boolean mDefaultNetwork; - final int mOemManaged; - - /** @hide */ - public NetworkIdentity( - int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey, - boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged, int subId) { - mType = type; - mRatType = ratType; - mSubscriberId = subscriberId; - mWifiNetworkKey = wifiNetworkKey; - mRoaming = roaming; - mMetered = metered; - mDefaultNetwork = defaultNetwork; - mOemManaged = oemManaged; - mSubId = subId; - } - - @Override - public int hashCode() { - return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered, - mDefaultNetwork, mOemManaged, mSubId); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof NetworkIdentity) { - final NetworkIdentity ident = (NetworkIdentity) obj; - return mType == ident.mType && mRatType == ident.mRatType && mRoaming == ident.mRoaming - && Objects.equals(mSubscriberId, ident.mSubscriberId) - && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey) - && mMetered == ident.mMetered - && mDefaultNetwork == ident.mDefaultNetwork - && mOemManaged == ident.mOemManaged - && mSubId == ident.mSubId; - } - return false; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder("{"); - builder.append("type=").append(mType); - builder.append(", ratType="); - if (mRatType == NETWORK_TYPE_ALL) { - builder.append("COMBINED"); - } else { - builder.append(mRatType); - } - if (mSubscriberId != null) { - builder.append(", subscriberId=") - .append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); - } - if (mWifiNetworkKey != null) { - builder.append(", wifiNetworkKey=").append(mWifiNetworkKey); - } - if (mRoaming) { - builder.append(", ROAMING"); - } - builder.append(", metered=").append(mMetered); - builder.append(", defaultNetwork=").append(mDefaultNetwork); - builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); - builder.append(", subId=").append(mSubId); - return builder.append("}").toString(); - } - - /** - * Get the human readable representation of a bitfield representing the OEM managed state of a - * network. - */ - static String getOemManagedNames(int oemManaged) { - if (oemManaged == OEM_NONE) { - return "OEM_NONE"; - } - final int[] bitPositions = NetworkCapabilitiesUtils.unpackBits(oemManaged); - final ArrayList<String> oemManagedNames = new ArrayList<String>(); - for (int position : bitPositions) { - oemManagedNames.add(nameOfOemManaged(1 << position)); - } - return String.join(",", oemManagedNames); - } - - private static String nameOfOemManaged(int oemManagedBit) { - switch (oemManagedBit) { - case OEM_PAID: - return "OEM_PAID"; - case OEM_PRIVATE: - return "OEM_PRIVATE"; - default: - return "Invalid(" + oemManagedBit + ")"; - } - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - proto.write(NetworkIdentityProto.TYPE, mType); - - // TODO: dump mRatType as well. - - proto.write(NetworkIdentityProto.ROAMING, mRoaming); - proto.write(NetworkIdentityProto.METERED, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); - - proto.end(start); - } - - /** Get the network type of this instance. */ - public int getType() { - return mType; - } - - /** Get the Radio Access Technology(RAT) type of this instance. */ - public int getRatType() { - return mRatType; - } - - /** Get the Subscriber Id of this instance. */ - @Nullable - public String getSubscriberId() { - return mSubscriberId; - } - - /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getNetworkKey()}. */ - @Nullable - public String getWifiNetworkKey() { - return mWifiNetworkKey; - } - - /** @hide */ - // TODO: Remove this function after all callers are removed. - public boolean getRoaming() { - return mRoaming; - } - - /** Return whether this network is roaming. */ - public boolean isRoaming() { - return mRoaming; - } - - /** @hide */ - // TODO: Remove this function after all callers are removed. - public boolean getMetered() { - return mMetered; - } - - /** Return whether this network is metered. */ - public boolean isMetered() { - return mMetered; - } - - /** @hide */ - // TODO: Remove this function after all callers are removed. - public boolean getDefaultNetwork() { - return mDefaultNetwork; - } - - /** Return whether this network is the default network. */ - public boolean isDefaultNetwork() { - return mDefaultNetwork; - } - - /** Get the OEM managed type of this instance. */ - public int getOemManaged() { - return mOemManaged; - } - - /** Get the SubId of this instance. */ - public int getSubId() { - return mSubId; - } - - /** - * Assemble a {@link NetworkIdentity} from the passed arguments. - * - * This methods builds an identity based on the capabilities of the network in the - * snapshot and other passed arguments. The identity is used as a key to record data usage. - * - * @param snapshot the snapshot of network state. See {@link NetworkStateSnapshot}. - * @param defaultNetwork whether the network is a default network. - * @param ratType the Radio Access Technology(RAT) type of the network. Or - * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if not applicable. - * See {@code TelephonyManager.NETWORK_TYPE_*}. - * @hide - * @deprecated See {@link NetworkIdentity.Builder}. - */ - // TODO: Remove this after all callers are migrated to use new Api. - @Deprecated - @NonNull - public static NetworkIdentity buildNetworkIdentity(Context context, - @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) { - final NetworkIdentity.Builder builder = new NetworkIdentity.Builder() - .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork) - .setSubId(snapshot.getSubId()); - if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) { - builder.setRatType(ratType); - } - return builder.build(); - } - - /** - * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}. - * @hide - */ - public static int getOemBitfield(@NonNull NetworkCapabilities nc) { - int oemManaged = OEM_NONE; - - if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) { - oemManaged |= OEM_PAID; - } - if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) { - oemManaged |= OEM_PRIVATE; - } - - return oemManaged; - } - - /** @hide */ - public static int compare(@NonNull NetworkIdentity left, @NonNull NetworkIdentity right) { - Objects.requireNonNull(right); - int res = Integer.compare(left.mType, right.mType); - if (res == 0) { - res = Integer.compare(left.mRatType, right.mRatType); - } - if (res == 0 && left.mSubscriberId != null && right.mSubscriberId != null) { - res = left.mSubscriberId.compareTo(right.mSubscriberId); - } - if (res == 0 && left.mWifiNetworkKey != null && right.mWifiNetworkKey != null) { - res = left.mWifiNetworkKey.compareTo(right.mWifiNetworkKey); - } - if (res == 0) { - res = Boolean.compare(left.mRoaming, right.mRoaming); - } - if (res == 0) { - res = Boolean.compare(left.mMetered, right.mMetered); - } - if (res == 0) { - res = Boolean.compare(left.mDefaultNetwork, right.mDefaultNetwork); - } - if (res == 0) { - res = Integer.compare(left.mOemManaged, right.mOemManaged); - } - if (res == 0) { - res = Integer.compare(left.mSubId, right.mSubId); - } - return res; - } - - /** - * Builder class for {@link NetworkIdentity}. - */ - public static final class Builder { - // Need to be synchronized with ConnectivityManager. - // TODO: Use {@link ConnectivityManager#MAX_NETWORK_TYPE} when this file is in the module. - private static final int MAX_NETWORK_TYPE = 18; // TYPE_TEST - private static final int MIN_NETWORK_TYPE = TYPE_MOBILE; - - private int mType; - private int mRatType; - private String mSubscriberId; - private String mWifiNetworkKey; - private boolean mRoaming; - private boolean mMetered; - private boolean mDefaultNetwork; - private int mOemManaged; - private int mSubId; - - /** - * Creates a new Builder. - */ - public Builder() { - // Initialize with default values. Will be overwritten by setters. - mType = ConnectivityManager.TYPE_NONE; - mRatType = NetworkTemplate.NETWORK_TYPE_ALL; - mSubscriberId = null; - mWifiNetworkKey = null; - mRoaming = false; - mMetered = false; - mDefaultNetwork = false; - mOemManaged = NetworkTemplate.OEM_MANAGED_NO; - mSubId = INVALID_SUBSCRIPTION_ID; - } - - /** - * Add an {@link NetworkStateSnapshot} into the {@link NetworkIdentity} instance. - * This is a useful shorthand that will read from the snapshot and set the - * following fields, if they are set in the snapshot : - * - type - * - subscriberId - * - roaming - * - metered - * - oemManaged - * - wifiNetworkKey - * - * @param snapshot The target {@link NetworkStateSnapshot} object. - * @return The builder object. - */ - @SuppressLint("MissingGetterMatchingBuilder") - @NonNull - public Builder setNetworkStateSnapshot(@NonNull NetworkStateSnapshot snapshot) { - setType(snapshot.getLegacyType()); - - setSubscriberId(snapshot.getSubscriberId()); - setRoaming(!snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)); - setMetered(!(snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED) - || snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED))); - - setOemManaged(getOemBitfield(snapshot.getNetworkCapabilities())); - - if (mType == TYPE_WIFI) { - final TransportInfo transportInfo = snapshot.getNetworkCapabilities() - .getTransportInfo(); - if (transportInfo instanceof WifiInfo) { - final WifiInfo info = (WifiInfo) transportInfo; - setWifiNetworkKey(info.getNetworkKey()); - } - } - return this; - } - - /** - * Set the network type of the network. - * - * @param type the network type. See {@link ConnectivityManager#TYPE_*}. - * - * @return this builder. - */ - @NonNull - public Builder setType(int type) { - // Include TYPE_NONE for compatibility, type field might not be filled by some - // networks such as test networks. - if ((type < MIN_NETWORK_TYPE || MAX_NETWORK_TYPE < type) - && type != ConnectivityManager.TYPE_NONE) { - throw new IllegalArgumentException("Invalid network type: " + type); - } - mType = type; - return this; - } - - /** - * Set the Radio Access Technology(RAT) type of the network. - * - * No RAT type is specified by default. Call clearRatType to reset. - * - * @param ratType the Radio Access Technology(RAT) type if applicable. See - * {@code TelephonyManager.NETWORK_TYPE_*}. - * - * @return this builder. - */ - @NonNull - public Builder setRatType(int ratType) { - if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType) - && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN - && ratType != NetworkStatsManager.NETWORK_TYPE_5G_NSA) { - throw new IllegalArgumentException("Invalid ratType " + ratType); - } - mRatType = ratType; - return this; - } - - /** - * Clear the Radio Access Technology(RAT) type of the network. - * - * @return this builder. - */ - @NonNull - public Builder clearRatType() { - mRatType = NetworkTemplate.NETWORK_TYPE_ALL; - return this; - } - - /** - * Set the Subscriber Id. - * - * @param subscriberId the Subscriber Id of the network. Or null if not applicable. - * @return this builder. - */ - @NonNull - public Builder setSubscriberId(@Nullable String subscriberId) { - mSubscriberId = subscriberId; - return this; - } - - /** - * Set the Wifi Network Key. - * - * @param wifiNetworkKey Wifi Network Key of the network, - * see {@link WifiInfo#getNetworkKey()}. - * Or null if not applicable. - * @return this builder. - */ - @NonNull - public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) { - mWifiNetworkKey = wifiNetworkKey; - return this; - } - - /** - * Set whether this network is roaming. - * - * This field is false by default. Call with false to reset. - * - * @param roaming the roaming status of the network. - * @return this builder. - */ - @NonNull - public Builder setRoaming(boolean roaming) { - mRoaming = roaming; - return this; - } - - /** - * Set whether this network is metered. - * - * This field is false by default. Call with false to reset. - * - * @param metered the meteredness of the network. - * @return this builder. - */ - @NonNull - public Builder setMetered(boolean metered) { - mMetered = metered; - return this; - } - - /** - * Set whether this network is the default network. - * - * This field is false by default. Call with false to reset. - * - * @param defaultNetwork the default network status of the network. - * @return this builder. - */ - @NonNull - public Builder setDefaultNetwork(boolean defaultNetwork) { - mDefaultNetwork = defaultNetwork; - return this; - } - - /** - * Set the OEM managed type. - * - * @param oemManaged Type of OEM managed network or unmanaged networks. - * See {@code NetworkTemplate#OEM_MANAGED_*}. - * @return this builder. - */ - @NonNull - public Builder setOemManaged(@OemManaged int oemManaged) { - // Assert input does not contain illegal oemManage bits. - if ((~SUPPORTED_OEM_MANAGED_TYPES & oemManaged) != 0) { - throw new IllegalArgumentException("Invalid value for OemManaged : " + oemManaged); - } - mOemManaged = oemManaged; - return this; - } - - /** - * Set the Subscription Id. - * - * @param subId the Subscription Id of the network. Or INVALID_SUBSCRIPTION_ID if not - * applicable. - * @return this builder. - */ - @NonNull - public Builder setSubId(int subId) { - mSubId = subId; - return this; - } - - private void ensureValidParameters() { - // Assert non-mobile network cannot have a ratType. - if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) { - throw new IllegalArgumentException( - "Invalid ratType " + mRatType + " for type " + mType); - } - - // Assert non-wifi network cannot have a wifi network key. - if (mType != TYPE_WIFI && mWifiNetworkKey != null) { - throw new IllegalArgumentException("Invalid wifi network key for type " + mType); - } - } - - /** - * Builds the instance of the {@link NetworkIdentity}. - * - * @return the built instance of {@link NetworkIdentity}. - */ - @NonNull - public NetworkIdentity build() { - ensureValidParameters(); - return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey, - mRoaming, mMetered, mDefaultNetwork, mOemManaged, mSubId); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java deleted file mode 100644 index ad3a958a680e..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; - -import android.annotation.NonNull; -import android.service.NetworkIdentitySetProto; -import android.util.proto.ProtoOutputStream; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} - * active on that interface. - * - * @hide - */ -public class NetworkIdentitySet extends HashSet<NetworkIdentity> { - private static final int VERSION_INIT = 1; - private static final int VERSION_ADD_ROAMING = 2; - private static final int VERSION_ADD_NETWORK_ID = 3; - private static final int VERSION_ADD_METERED = 4; - private static final int VERSION_ADD_DEFAULT_NETWORK = 5; - private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; - private static final int VERSION_ADD_SUB_ID = 7; - - /** - * Construct a {@link NetworkIdentitySet} object. - */ - public NetworkIdentitySet() { - super(); - } - - /** @hide */ - public NetworkIdentitySet(@NonNull Set<NetworkIdentity> ident) { - super(ident); - } - - /** @hide */ - public NetworkIdentitySet(DataInput in) throws IOException { - final int version = in.readInt(); - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - if (version <= VERSION_INIT) { - final int ignored = in.readInt(); - } - final int type = in.readInt(); - final int ratType = in.readInt(); - final String subscriberId = readOptionalString(in); - final String networkId; - if (version >= VERSION_ADD_NETWORK_ID) { - networkId = readOptionalString(in); - } else { - networkId = null; - } - final boolean roaming; - if (version >= VERSION_ADD_ROAMING) { - roaming = in.readBoolean(); - } else { - roaming = false; - } - - final boolean metered; - if (version >= VERSION_ADD_METERED) { - metered = in.readBoolean(); - } else { - // If this is the old data and the type is mobile, treat it as metered. (Note that - // if this is a mobile network, TYPE_MOBILE is the only possible type that could be - // used.) - metered = (type == TYPE_MOBILE); - } - - final boolean defaultNetwork; - if (version >= VERSION_ADD_DEFAULT_NETWORK) { - defaultNetwork = in.readBoolean(); - } else { - defaultNetwork = true; - } - - final int oemNetCapabilities; - if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) { - oemNetCapabilities = in.readInt(); - } else { - oemNetCapabilities = NetworkIdentity.OEM_NONE; - } - - final int subId; - if (version >= VERSION_ADD_SUB_ID) { - subId = in.readInt(); - } else { - subId = INVALID_SUBSCRIPTION_ID; - } - - add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered, - defaultNetwork, oemNetCapabilities, subId)); - } - } - - /** - * Method to serialize this object into a {@code DataOutput}. - * @hide - */ - public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_SUB_ID); - out.writeInt(size()); - for (NetworkIdentity ident : this) { - out.writeInt(ident.getType()); - out.writeInt(ident.getRatType()); - writeOptionalString(out, ident.getSubscriberId()); - writeOptionalString(out, ident.getWifiNetworkKey()); - out.writeBoolean(ident.isRoaming()); - out.writeBoolean(ident.isMetered()); - out.writeBoolean(ident.isDefaultNetwork()); - out.writeInt(ident.getOemManaged()); - out.writeInt(ident.getSubId()); - } - } - - /** - * @return whether any {@link NetworkIdentity} in this set is considered metered. - * @hide - */ - public boolean isAnyMemberMetered() { - if (isEmpty()) { - return false; - } - for (NetworkIdentity ident : this) { - if (ident.isMetered()) { - return true; - } - } - return false; - } - - /** - * @return whether any {@link NetworkIdentity} in this set is considered roaming. - * @hide - */ - public boolean isAnyMemberRoaming() { - if (isEmpty()) { - return false; - } - for (NetworkIdentity ident : this) { - if (ident.isRoaming()) { - return true; - } - } - return false; - } - - /** - * @return whether any {@link NetworkIdentity} in this set is considered on the default - * network. - * @hide - */ - public boolean areAllMembersOnDefaultNetwork() { - if (isEmpty()) { - return true; - } - for (NetworkIdentity ident : this) { - if (!ident.isDefaultNetwork()) { - return false; - } - } - return true; - } - - private static void writeOptionalString(DataOutput out, String value) throws IOException { - if (value != null) { - out.writeByte(1); - out.writeUTF(value); - } else { - out.writeByte(0); - } - } - - private static String readOptionalString(DataInput in) throws IOException { - if (in.readByte() != 0) { - return in.readUTF(); - } else { - return null; - } - } - - public static int compare(@NonNull NetworkIdentitySet left, @NonNull NetworkIdentitySet right) { - Objects.requireNonNull(left); - Objects.requireNonNull(right); - if (left.isEmpty()) return -1; - if (right.isEmpty()) return 1; - - final NetworkIdentity leftIdent = left.iterator().next(); - final NetworkIdentity rightIdent = right.iterator().next(); - return NetworkIdentity.compare(leftIdent, rightIdent); - } - - /** - * Method to dump this object into proto debug file. - * @hide - */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); - } - - proto.end(start); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java deleted file mode 100644 index c018e916551e..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java +++ /dev/null @@ -1,192 +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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.net.module.util.NetworkIdentityUtils; - -import java.util.Objects; - -/** - * Snapshot of network state. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class NetworkStateSnapshot implements Parcelable { - /** The network associated with this snapshot. */ - @NonNull - private final Network mNetwork; - - /** The {@link NetworkCapabilities} of the network associated with this snapshot. */ - @NonNull - private final NetworkCapabilities mNetworkCapabilities; - - /** The {@link LinkProperties} of the network associated with this snapshot. */ - @NonNull - private final LinkProperties mLinkProperties; - - /** - * The Subscriber Id of the network associated with this snapshot. See - * {@link android.telephony.TelephonyManager#getSubscriberId()}. - */ - @Nullable - private final String mSubscriberId; - - /** - * The legacy type of the network associated with this snapshot. See - * {@code ConnectivityManager#TYPE_*}. - */ - private final int mLegacyType; - - public NetworkStateSnapshot(@NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull LinkProperties linkProperties, - @Nullable String subscriberId, int legacyType) { - mNetwork = Objects.requireNonNull(network); - mNetworkCapabilities = Objects.requireNonNull(networkCapabilities); - mLinkProperties = Objects.requireNonNull(linkProperties); - mSubscriberId = subscriberId; - mLegacyType = legacyType; - } - - /** @hide */ - public NetworkStateSnapshot(@NonNull Parcel in) { - mNetwork = in.readParcelable(null, android.net.Network.class); - mNetworkCapabilities = in.readParcelable(null, android.net.NetworkCapabilities.class); - mLinkProperties = in.readParcelable(null, android.net.LinkProperties.class); - mSubscriberId = in.readString(); - mLegacyType = in.readInt(); - } - - /** Get the network associated with this snapshot */ - @NonNull - public Network getNetwork() { - return mNetwork; - } - - /** Get {@link NetworkCapabilities} of the network associated with this snapshot. */ - @NonNull - public NetworkCapabilities getNetworkCapabilities() { - return mNetworkCapabilities; - } - - /** Get the {@link LinkProperties} of the network associated with this snapshot. */ - @NonNull - public LinkProperties getLinkProperties() { - return mLinkProperties; - } - - /** - * Get the Subscriber Id of the network associated with this snapshot. - * @deprecated Please use #getSubId, which doesn't return personally identifiable - * information. - */ - @Deprecated - @Nullable - public String getSubscriberId() { - return mSubscriberId; - } - - /** Get the subId of the network associated with this snapshot. */ - public int getSubId() { - if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { - final NetworkSpecifier spec = mNetworkCapabilities.getNetworkSpecifier(); - if (spec instanceof TelephonyNetworkSpecifier) { - return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); - } - } - return INVALID_SUBSCRIPTION_ID; - } - - - /** - * Get the legacy type of the network associated with this snapshot. - * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}. - */ - public int getLegacyType() { - return mLegacyType; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(mNetwork, flags); - out.writeParcelable(mNetworkCapabilities, flags); - out.writeParcelable(mLinkProperties, flags); - out.writeString(mSubscriberId); - out.writeInt(mLegacyType); - } - - @NonNull - public static final Creator<NetworkStateSnapshot> CREATOR = - new Creator<NetworkStateSnapshot>() { - @NonNull - @Override - public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) { - return new NetworkStateSnapshot(in); - } - - @NonNull - @Override - public NetworkStateSnapshot[] newArray(int size) { - return new NetworkStateSnapshot[size]; - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof NetworkStateSnapshot)) return false; - NetworkStateSnapshot that = (NetworkStateSnapshot) o; - return mLegacyType == that.mLegacyType - && Objects.equals(mNetwork, that.mNetwork) - && Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities) - && Objects.equals(mLinkProperties, that.mLinkProperties) - && Objects.equals(mSubscriberId, that.mSubscriberId); - } - - @Override - public int hashCode() { - return Objects.hash(mNetwork, - mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType); - } - - @Override - public String toString() { - return "NetworkStateSnapshot{" - + "network=" + mNetwork - + ", networkCapabilities=" + mNetworkCapabilities - + ", linkProperties=" + mLinkProperties - + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\'' - + ", legacyType=" + mLegacyType - + '}'; - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java deleted file mode 100644 index bcfeab96081a..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java +++ /dev/null @@ -1,1860 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.Process; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.SparseBooleanArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.CollectionUtils; - -import libcore.util.EmptyArray; - -import java.io.CharArrayWriter; -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Predicate; - -/** - * Collection of active network statistics. Can contain summary details across - * all interfaces, or details with per-UID granularity. Internally stores data - * as a large table, closely matching {@code /proc/} data format. This structure - * optimizes for rapid in-memory comparison, but consider using - * {@link NetworkStatsHistory} when persisting. - * - * @hide - */ -// @NotThreadSafe -@SystemApi -public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Entry> { - private static final String TAG = "NetworkStats"; - - /** - * {@link #iface} value when interface details unavailable. - * @hide - */ - @Nullable public static final String IFACE_ALL = null; - - /** - * Virtual network interface for video telephony. This is for VT data usage counting - * purpose. - */ - public static final String IFACE_VT = "vt_data0"; - - /** {@link #uid} value when UID details unavailable. */ - public static final int UID_ALL = -1; - /** Special UID value for data usage by tethering. */ - public static final int UID_TETHERING = -5; - - /** - * {@link #tag} value matching any tag. - * @hide - */ - // TODO: Rename TAG_ALL to TAG_ANY. - public static final int TAG_ALL = -1; - /** {@link #set} value for all sets combined, not including debug sets. */ - public static final int SET_ALL = -1; - /** {@link #set} value where background data is accounted. */ - public static final int SET_DEFAULT = 0; - /** {@link #set} value where foreground data is accounted. */ - public static final int SET_FOREGROUND = 1; - /** - * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. - * @hide - */ - public static final int SET_DEBUG_START = 1000; - /** - * Debug {@link #set} value when the VPN stats are moved in. - * @hide - */ - public static final int SET_DBG_VPN_IN = 1001; - /** - * Debug {@link #set} value when the VPN stats are moved out of a vpn UID. - * @hide - */ - public static final int SET_DBG_VPN_OUT = 1002; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "SET_" }, value = { - SET_ALL, - SET_DEFAULT, - SET_FOREGROUND, - }) - public @interface State { - } - - /** - * Include all interfaces when filtering - * @hide - */ - public @Nullable static final String[] INTERFACES_ALL = null; - - /** {@link #tag} value for total data across all tags. */ - public static final int TAG_NONE = 0; - - /** {@link #metered} value to account for all metered states. */ - public static final int METERED_ALL = -1; - /** {@link #metered} value where native, unmetered data is accounted. */ - public static final int METERED_NO = 0; - /** {@link #metered} value where metered data is accounted. */ - public static final int METERED_YES = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "METERED_" }, value = { - METERED_ALL, - METERED_NO, - METERED_YES - }) - public @interface Meteredness { - } - - - /** {@link #roaming} value to account for all roaming states. */ - public static final int ROAMING_ALL = -1; - /** {@link #roaming} value where native, non-roaming data is accounted. */ - public static final int ROAMING_NO = 0; - /** {@link #roaming} value where roaming data is accounted. */ - public static final int ROAMING_YES = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "ROAMING_" }, value = { - ROAMING_ALL, - ROAMING_NO, - ROAMING_YES - }) - public @interface Roaming { - } - - /** {@link #onDefaultNetwork} value to account for all default network states. */ - public static final int DEFAULT_NETWORK_ALL = -1; - /** {@link #onDefaultNetwork} value to account for usage while not the default network. */ - public static final int DEFAULT_NETWORK_NO = 0; - /** {@link #onDefaultNetwork} value to account for usage while the default network. */ - public static final int DEFAULT_NETWORK_YES = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { - DEFAULT_NETWORK_ALL, - DEFAULT_NETWORK_NO, - DEFAULT_NETWORK_YES - }) - public @interface DefaultNetwork { - } - - /** - * Denotes a request for stats at the interface level. - * @hide - */ - public static final int STATS_PER_IFACE = 0; - /** - * Denotes a request for stats at the interface and UID level. - * @hide - */ - public static final int STATS_PER_UID = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "STATS_PER_" }, value = { - STATS_PER_IFACE, - STATS_PER_UID - }) - public @interface StatsType { - } - - private static final String CLATD_INTERFACE_PREFIX = "v4-"; - // Delta between IPv4 header (20b) and IPv6 header (40b). - // Used for correct stats accounting on clatd interfaces. - private static final int IPV4V6_HEADER_DELTA = 20; - - // TODO: move fields to "mVariable" notation - - /** - * {@link SystemClock#elapsedRealtime()} timestamp in milliseconds when this data was - * generated. - * It's a timestamps delta when {@link #subtract()}, - * {@code INetworkStatsSession#getSummaryForAllUid()} methods are used. - */ - private long elapsedRealtime; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int size; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int capacity; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private String[] iface; - @UnsupportedAppUsage - private int[] uid; - @UnsupportedAppUsage - private int[] set; - @UnsupportedAppUsage - private int[] tag; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int[] metered; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int[] roaming; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int[] defaultNetwork; - @UnsupportedAppUsage - private long[] rxBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long[] rxPackets; - @UnsupportedAppUsage - private long[] txBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long[] txPackets; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long[] operations; - - /** - * Basic element of network statistics. Contains the number of packets and number of bytes - * transferred on both directions in a given set of conditions. See - * {@link Entry#Entry(String, int, int, int, int, int, int, long, long, long, long, long)}. - * - * @hide - */ - @SystemApi - public static class Entry { - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String iface; - /** @hide */ - @UnsupportedAppUsage - public int uid; - /** @hide */ - @UnsupportedAppUsage - public int set; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int tag; - /** - * Note that this is only populated w/ the default value when read from /proc or written - * to disk. We merge in the correct value when reporting this value to clients of - * getSummary(). - * @hide - */ - public int metered; - /** - * Note that this is only populated w/ the default value when read from /proc or written - * to disk. We merge in the correct value when reporting this value to clients of - * getSummary(). - * @hide - */ - public int roaming; - /** - * Note that this is only populated w/ the default value when read from /proc or written - * to disk. We merge in the correct value when reporting this value to clients of - * getSummary(). - * @hide - */ - public int defaultNetwork; - /** @hide */ - @UnsupportedAppUsage - public long rxBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long rxPackets; - /** @hide */ - @UnsupportedAppUsage - public long txBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long txPackets; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long operations; - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public Entry() { - this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); - } - - /** @hide */ - public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, - operations); - } - - /** @hide */ - public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, - rxBytes, rxPackets, txBytes, txPackets, operations); - } - - /** - * Construct a {@link Entry} object by giving statistics of packet and byte transferred on - * both direction, and associated with a set of given conditions. - * - * @param iface interface name of this {@link Entry}. Or null if not specified. - * @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is - * for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only - * counting iface stats. - * @param set usage state of this {@link Entry}. - * @param tag tag of this {@link Entry}. - * @param metered metered state of this {@link Entry}. - * @param roaming roaming state of this {@link Entry}. - * @param defaultNetwork default network status of this {@link Entry}. - * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param rxPackets Number of packets received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param operations count of network operations performed for this {@link Entry}. This can - * be used to derive bytes-per-operation. - */ - public Entry(@Nullable String iface, int uid, @State int set, int tag, - @Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this.iface = iface; - this.uid = uid; - this.set = set; - this.tag = tag; - this.metered = metered; - this.roaming = roaming; - this.defaultNetwork = defaultNetwork; - this.rxBytes = rxBytes; - this.rxPackets = rxPackets; - this.txBytes = txBytes; - this.txPackets = txPackets; - this.operations = operations; - } - - /** @hide */ - public boolean isNegative() { - return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0; - } - - /** @hide */ - public boolean isEmpty() { - return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0 - && operations == 0; - } - - /** @hide */ - public void add(Entry another) { - this.rxBytes += another.rxBytes; - this.rxPackets += another.rxPackets; - this.txBytes += another.txBytes; - this.txPackets += another.txPackets; - this.operations += another.operations; - } - - /** - * @return interface name of this entry. - * @hide - */ - @Nullable public String getIface() { - return iface; - } - - /** - * @return the uid of this entry. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public int getUid() { - return uid; - } - - /** - * @return the set state of this entry. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @State public int getSet() { - return set; - } - - /** - * @return the tag value of this entry. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public int getTag() { - return tag; - } - - /** - * @return the metered state. - * @hide - */ - @Meteredness - @SystemApi(client = MODULE_LIBRARIES) - public int getMetered() { - return metered; - } - - /** - * @return the roaming state. - * @hide - */ - @Roaming - @SystemApi(client = MODULE_LIBRARIES) - public int getRoaming() { - return roaming; - } - - /** - * @return the default network state. - * @hide - */ - @DefaultNetwork - @SystemApi(client = MODULE_LIBRARIES) - public int getDefaultNetwork() { - return defaultNetwork; - } - - /** - * @return the number of received bytes. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public long getRxBytes() { - return rxBytes; - } - - /** - * @return the number of received packets. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public long getRxPackets() { - return rxPackets; - } - - /** - * @return the number of transmitted bytes. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public long getTxBytes() { - return txBytes; - } - - /** - * @return the number of transmitted packets. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public long getTxPackets() { - return txPackets; - } - - /** - * @return the count of network operations performed for this entry. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public long getOperations() { - return operations; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("iface=").append(iface); - builder.append(" uid=").append(uid); - builder.append(" set=").append(setToString(set)); - builder.append(" tag=").append(tagToString(tag)); - builder.append(" metered=").append(meteredToString(metered)); - builder.append(" roaming=").append(roamingToString(roaming)); - builder.append(" defaultNetwork=").append(defaultNetworkToString(defaultNetwork)); - builder.append(" rxBytes=").append(rxBytes); - builder.append(" rxPackets=").append(rxPackets); - builder.append(" txBytes=").append(txBytes); - builder.append(" txPackets=").append(txPackets); - builder.append(" operations=").append(operations); - return builder.toString(); - } - - /** @hide */ - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof Entry) { - final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered - && roaming == e.roaming && defaultNetwork == e.defaultNetwork - && rxBytes == e.rxBytes && rxPackets == e.rxPackets - && txBytes == e.txBytes && txPackets == e.txPackets - && operations == e.operations && TextUtils.equals(iface, e.iface); - } - return false; - } - - /** @hide */ - @Override - public int hashCode() { - return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface); - } - } - - public NetworkStats(long elapsedRealtime, int initialSize) { - this.elapsedRealtime = elapsedRealtime; - this.size = 0; - if (initialSize > 0) { - this.capacity = initialSize; - this.iface = new String[initialSize]; - this.uid = new int[initialSize]; - this.set = new int[initialSize]; - this.tag = new int[initialSize]; - this.metered = new int[initialSize]; - this.roaming = new int[initialSize]; - this.defaultNetwork = new int[initialSize]; - this.rxBytes = new long[initialSize]; - this.rxPackets = new long[initialSize]; - this.txBytes = new long[initialSize]; - this.txPackets = new long[initialSize]; - this.operations = new long[initialSize]; - } else { - // Special case for use by NetworkStatsFactory to start out *really* empty. - clear(); - } - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public NetworkStats(Parcel parcel) { - elapsedRealtime = parcel.readLong(); - size = parcel.readInt(); - capacity = parcel.readInt(); - iface = parcel.createStringArray(); - uid = parcel.createIntArray(); - set = parcel.createIntArray(); - tag = parcel.createIntArray(); - metered = parcel.createIntArray(); - roaming = parcel.createIntArray(); - defaultNetwork = parcel.createIntArray(); - rxBytes = parcel.createLongArray(); - rxPackets = parcel.createLongArray(); - txBytes = parcel.createLongArray(); - txPackets = parcel.createLongArray(); - operations = parcel.createLongArray(); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeLong(elapsedRealtime); - dest.writeInt(size); - dest.writeInt(capacity); - dest.writeStringArray(iface); - dest.writeIntArray(uid); - dest.writeIntArray(set); - dest.writeIntArray(tag); - dest.writeIntArray(metered); - dest.writeIntArray(roaming); - dest.writeIntArray(defaultNetwork); - dest.writeLongArray(rxBytes); - dest.writeLongArray(rxPackets); - dest.writeLongArray(txBytes); - dest.writeLongArray(txPackets); - dest.writeLongArray(operations); - } - - /** - * @hide - */ - @Override - public NetworkStats clone() { - final NetworkStats clone = new NetworkStats(elapsedRealtime, size); - NetworkStats.Entry entry = null; - for (int i = 0; i < size; i++) { - entry = getValues(i, entry); - clone.insertEntry(entry); - } - return clone; - } - - /** - * Clear all data stored in this object. - * @hide - */ - public void clear() { - this.capacity = 0; - this.iface = EmptyArray.STRING; - this.uid = EmptyArray.INT; - this.set = EmptyArray.INT; - this.tag = EmptyArray.INT; - this.metered = EmptyArray.INT; - this.roaming = EmptyArray.INT; - this.defaultNetwork = EmptyArray.INT; - this.rxBytes = EmptyArray.LONG; - this.rxPackets = EmptyArray.LONG; - this.txBytes = EmptyArray.LONG; - this.txPackets = EmptyArray.LONG; - this.operations = EmptyArray.LONG; - } - - /** @hide */ - @VisibleForTesting - public NetworkStats insertEntry( - String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return insertEntry( - iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); - } - - /** @hide */ - @VisibleForTesting - public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { - return insertEntry(new Entry( - iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); - } - - /** @hide */ - @VisibleForTesting - public NetworkStats insertEntry(String iface, int uid, int set, int tag, int metered, - int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, - long txPackets, long operations) { - return insertEntry(new Entry( - iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, - txBytes, txPackets, operations)); - } - - /** - * Add new stats entry, copying from given {@link Entry}. The {@link Entry} - * object can be recycled across multiple calls. - * @hide - */ - public NetworkStats insertEntry(Entry entry) { - if (size >= capacity) { - final int newLength = Math.max(size, 10) * 3 / 2; - iface = Arrays.copyOf(iface, newLength); - uid = Arrays.copyOf(uid, newLength); - set = Arrays.copyOf(set, newLength); - tag = Arrays.copyOf(tag, newLength); - metered = Arrays.copyOf(metered, newLength); - roaming = Arrays.copyOf(roaming, newLength); - defaultNetwork = Arrays.copyOf(defaultNetwork, newLength); - rxBytes = Arrays.copyOf(rxBytes, newLength); - rxPackets = Arrays.copyOf(rxPackets, newLength); - txBytes = Arrays.copyOf(txBytes, newLength); - txPackets = Arrays.copyOf(txPackets, newLength); - operations = Arrays.copyOf(operations, newLength); - capacity = newLength; - } - - setValues(size, entry); - size++; - - return this; - } - - private void setValues(int i, Entry entry) { - iface[i] = entry.iface; - uid[i] = entry.uid; - set[i] = entry.set; - tag[i] = entry.tag; - metered[i] = entry.metered; - roaming[i] = entry.roaming; - defaultNetwork[i] = entry.defaultNetwork; - rxBytes[i] = entry.rxBytes; - rxPackets[i] = entry.rxPackets; - txBytes[i] = entry.txBytes; - txPackets[i] = entry.txPackets; - operations[i] = entry.operations; - } - - /** - * Iterate over Entry objects. - * - * Return an iterator of this object that will iterate through all contained Entry objects. - * - * This iterator does not support concurrent modification and makes no guarantee of fail-fast - * behavior. If any method that can mutate the contents of this object is called while - * iteration is in progress, either inside the loop or in another thread, then behavior is - * undefined. - * The remove() method is not implemented and will throw UnsupportedOperationException. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @NonNull public Iterator<Entry> iterator() { - return new Iterator<Entry>() { - int mIndex = 0; - - @Override - public boolean hasNext() { - return mIndex < size; - } - - @Override - public Entry next() { - return getValues(mIndex++, null); - } - }; - } - - /** - * Return specific stats entry. - * @hide - */ - @UnsupportedAppUsage - public Entry getValues(int i, @Nullable Entry recycle) { - final Entry entry = recycle != null ? recycle : new Entry(); - entry.iface = iface[i]; - entry.uid = uid[i]; - entry.set = set[i]; - entry.tag = tag[i]; - entry.metered = metered[i]; - entry.roaming = roaming[i]; - entry.defaultNetwork = defaultNetwork[i]; - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - entry.operations = operations[i]; - return entry; - } - - /** - * If @{code dest} is not equal to @{code src}, copy entry from index @{code src} to index - * @{code dest}. - */ - private void maybeCopyEntry(int dest, int src) { - if (dest == src) return; - iface[dest] = iface[src]; - uid[dest] = uid[src]; - set[dest] = set[src]; - tag[dest] = tag[src]; - metered[dest] = metered[src]; - roaming[dest] = roaming[src]; - defaultNetwork[dest] = defaultNetwork[src]; - rxBytes[dest] = rxBytes[src]; - rxPackets[dest] = rxPackets[src]; - txBytes[dest] = txBytes[src]; - txPackets[dest] = txPackets[src]; - operations[dest] = operations[src]; - } - - /** @hide */ - public long getElapsedRealtime() { - return elapsedRealtime; - } - - /** @hide */ - public void setElapsedRealtime(long time) { - elapsedRealtime = time; - } - - /** - * Return age of this {@link NetworkStats} object with respect to - * {@link SystemClock#elapsedRealtime()}. - * @hide - */ - public long getElapsedRealtimeAge() { - return SystemClock.elapsedRealtime() - elapsedRealtime; - } - - /** @hide */ - @UnsupportedAppUsage - public int size() { - return size; - } - - /** @hide */ - @VisibleForTesting - public int internalSize() { - return capacity; - } - - /** @hide */ - @Deprecated - public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, long operations) { - return combineValues( - iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, - txPackets, operations); - } - - /** @hide */ - public NetworkStats combineValues(String iface, int uid, int set, int tag, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return combineValues(new Entry( - iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); - } - - /** - * Combine given values with an existing row, or create a new row if - * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can - * also be used to subtract values from existing rows. This method mutates the referencing - * {@link NetworkStats} object. - * - * @param entry the {@link Entry} to combine. - * @return a reference to this mutated {@link NetworkStats} object. - * @hide - */ - public @NonNull NetworkStats combineValues(@NonNull Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, - entry.roaming, entry.defaultNetwork); - if (i == -1) { - // only create new entry when positive contribution - insertEntry(entry); - } else { - rxBytes[i] += entry.rxBytes; - rxPackets[i] += entry.rxPackets; - txBytes[i] += entry.txBytes; - txPackets[i] += entry.txPackets; - operations[i] += entry.operations; - } - return this; - } - - /** - * Add given values with an existing row, or create a new row if - * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can - * also be used to subtract values from existing rows. - * - * @param entry the {@link Entry} to add. - * @return a new constructed {@link NetworkStats} object that contains the result. - */ - public @NonNull NetworkStats addEntry(@NonNull Entry entry) { - return this.clone().combineValues(entry); - } - - /** - * Add the given {@link NetworkStats} objects. - * - * @return the sum of two objects. - */ - public @NonNull NetworkStats add(@NonNull NetworkStats another) { - final NetworkStats ret = this.clone(); - ret.combineAllValues(another); - return ret; - } - - /** - * Combine all values from another {@link NetworkStats} into this object. - * @hide - */ - public void combineAllValues(@NonNull NetworkStats another) { - NetworkStats.Entry entry = null; - for (int i = 0; i < another.size; i++) { - entry = another.getValues(i, entry); - combineValues(entry); - } - } - - /** - * Find first stats index that matches the requested parameters. - * @hide - */ - public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork) { - for (int i = 0; i < size; i++) { - if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && metered == this.metered[i] && roaming == this.roaming[i] - && defaultNetwork == this.defaultNetwork[i] - && Objects.equals(iface, this.iface[i])) { - return i; - } - } - return -1; - } - - /** - * Find first stats index that matches the requested parameters, starting - * search around the hinted index as an optimization. - * @hide - */ - @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork, int hintIndex) { - for (int offset = 0; offset < size; offset++) { - final int halfOffset = offset / 2; - - // search outwards from hint index, alternating forward and backward - final int i; - if (offset % 2 == 0) { - i = (hintIndex + halfOffset) % size; - } else { - i = (size + hintIndex - halfOffset - 1) % size; - } - - if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && metered == this.metered[i] && roaming == this.roaming[i] - && defaultNetwork == this.defaultNetwork[i] - && Objects.equals(iface, this.iface[i])) { - return i; - } - } - return -1; - } - - /** - * Splice in {@link #operations} from the given {@link NetworkStats} based - * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface}, - * since operation counts are at data layer. - * @hide - */ - public void spliceOperationsFrom(NetworkStats stats) { - for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i], - defaultNetwork[i]); - if (j == -1) { - operations[i] = 0; - } else { - operations[i] = stats.operations[j]; - } - } - } - - /** - * Return list of unique interfaces known by this data structure. - * @hide - */ - public String[] getUniqueIfaces() { - final HashSet<String> ifaces = new HashSet<String>(); - for (String iface : this.iface) { - if (iface != IFACE_ALL) { - ifaces.add(iface); - } - } - return ifaces.toArray(new String[ifaces.size()]); - } - - /** - * Return list of unique UIDs known by this data structure. - * @hide - */ - @UnsupportedAppUsage - public int[] getUniqueUids() { - final SparseBooleanArray uids = new SparseBooleanArray(); - for (int uid : this.uid) { - uids.put(uid, true); - } - - final int size = uids.size(); - final int[] result = new int[size]; - for (int i = 0; i < size; i++) { - result[i] = uids.keyAt(i); - } - return result; - } - - /** - * Return total bytes represented by this snapshot object, usually used when - * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. - * @hide - */ - @UnsupportedAppUsage - public long getTotalBytes() { - final Entry entry = getTotal(null); - return entry.rxBytes + entry.txBytes; - } - - /** - * Return total of all fields represented by this snapshot object. - * @hide - */ - @UnsupportedAppUsage - public Entry getTotal(Entry recycle) { - return getTotal(recycle, null, UID_ALL, false); - } - - /** - * Return total of all fields represented by this snapshot object matching - * the requested {@link #uid}. - * @hide - */ - @UnsupportedAppUsage - public Entry getTotal(Entry recycle, int limitUid) { - return getTotal(recycle, null, limitUid, false); - } - - /** - * Return total of all fields represented by this snapshot object matching - * the requested {@link #iface}. - * @hide - */ - public Entry getTotal(Entry recycle, HashSet<String> limitIface) { - return getTotal(recycle, limitIface, UID_ALL, false); - } - - /** @hide */ - @UnsupportedAppUsage - public Entry getTotalIncludingTags(Entry recycle) { - return getTotal(recycle, null, UID_ALL, true); - } - - /** - * Return total of all fields represented by this snapshot object matching - * the requested {@link #iface} and {@link #uid}. - * - * @param limitIface Set of {@link #iface} to include in total; or {@code - * null} to include all ifaces. - */ - private Entry getTotal( - Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) { - final Entry entry = recycle != null ? recycle : new Entry(); - - entry.iface = IFACE_ALL; - entry.uid = limitUid; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.metered = METERED_ALL; - entry.roaming = ROAMING_ALL; - entry.defaultNetwork = DEFAULT_NETWORK_ALL; - entry.rxBytes = 0; - entry.rxPackets = 0; - entry.txBytes = 0; - entry.txPackets = 0; - entry.operations = 0; - - for (int i = 0; i < size; i++) { - final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]); - final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i])); - - if (matchesUid && matchesIface) { - // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE && !includeTags) continue; - - entry.rxBytes += rxBytes[i]; - entry.rxPackets += rxPackets[i]; - entry.txBytes += txBytes[i]; - entry.txPackets += txPackets[i]; - entry.operations += operations[i]; - } - } - return entry; - } - - /** - * Fast path for battery stats. - * @hide - */ - public long getTotalPackets() { - long total = 0; - for (int i = size-1; i >= 0; i--) { - total += rxPackets[i] + txPackets[i]; - } - return total; - } - - /** - * Subtract the given {@link NetworkStats}, effectively leaving the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. This method does not mutate - * the referencing object. - * - * @return the delta between two objects. - */ - public @NonNull NetworkStats subtract(@NonNull NetworkStats right) { - return subtract(this, right, null, null); - } - - /** - * Subtract the two given {@link NetworkStats} objects, returning the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. - * <p> - * If counters have rolled backwards, they are clamped to {@code 0} and - * reported to the given {@link NonMonotonicObserver}. - * @hide - */ - public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, - NonMonotonicObserver<C> observer, C cookie) { - return subtract(left, right, observer, cookie, null); - } - - /** - * Subtract the two given {@link NetworkStats} objects, returning the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. - * <p> - * If counters have rolled backwards, they are clamped to {@code 0} and - * reported to the given {@link NonMonotonicObserver}. - * <p> - * If <var>recycle</var> is supplied, this NetworkStats object will be - * reused (and returned) as the result if it is large enough to contain - * the data. - * @hide - */ - public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right, - NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) { - long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime; - if (deltaRealtime < 0) { - if (observer != null) { - observer.foundNonMonotonic(left, -1, right, -1, cookie); - } - deltaRealtime = 0; - } - - // result will have our rows, and elapsed time between snapshots - final Entry entry = new Entry(); - final NetworkStats result; - if (recycle != null && recycle.capacity >= left.size) { - result = recycle; - result.size = 0; - result.elapsedRealtime = deltaRealtime; - } else { - result = new NetworkStats(deltaRealtime, left.size); - } - for (int i = 0; i < left.size; i++) { - entry.iface = left.iface[i]; - entry.uid = left.uid[i]; - entry.set = left.set[i]; - entry.tag = left.tag[i]; - entry.metered = left.metered[i]; - entry.roaming = left.roaming[i]; - entry.defaultNetwork = left.defaultNetwork[i]; - entry.rxBytes = left.rxBytes[i]; - entry.rxPackets = left.rxPackets[i]; - entry.txBytes = left.txBytes[i]; - entry.txPackets = left.txPackets[i]; - entry.operations = left.operations[i]; - - // find remote row that matches, and subtract - final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.metered, entry.roaming, entry.defaultNetwork, i); - if (j != -1) { - // Found matching row, subtract remote value. - entry.rxBytes -= right.rxBytes[j]; - entry.rxPackets -= right.rxPackets[j]; - entry.txBytes -= right.txBytes[j]; - entry.txPackets -= right.txPackets[j]; - entry.operations -= right.operations[j]; - } - - if (entry.isNegative()) { - if (observer != null) { - observer.foundNonMonotonic(left, i, right, j, cookie); - } - entry.rxBytes = Math.max(entry.rxBytes, 0); - entry.rxPackets = Math.max(entry.rxPackets, 0); - entry.txBytes = Math.max(entry.txBytes, 0); - entry.txPackets = Math.max(entry.txPackets, 0); - entry.operations = Math.max(entry.operations, 0); - } - - result.insertEntry(entry); - } - - return result; - } - - /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic. - * - * <p>This mutates stacked traffic stats, to account for IPv4/IPv6 header size difference. - * - * <p>UID stats, which are only accounted on the stacked interface, need to be increased - * by 20 bytes/packet to account for translation overhead. - * - * <p>The potential additional overhead of 8 bytes/packet for ip fragments is ignored. - * - * <p>Interface stats need to sum traffic on both stacked and base interface because: - * - eBPF offloaded packets appear only on the stacked interface - * - Non-offloaded ingress packets appear only on the stacked interface - * (due to iptables raw PREROUTING drop rules) - * - Non-offloaded egress packets appear only on the stacked interface - * (due to ignoring traffic from clat daemon by uid match) - * (and of course the 20 bytes/packet overhead needs to be applied to stacked interface stats) - * - * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only - * {@code ConcurrentHashMap} - * @param baseTraffic Traffic on the base interfaces. Will be mutated. - * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. - * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @hide - */ - public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map<String, String> stackedIfaces) { - // For recycling - Entry entry = null; - for (int i = 0; i < stackedTraffic.size; i++) { - entry = stackedTraffic.getValues(i, entry); - if (entry == null) continue; - if (entry.iface == null) continue; - if (!entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) continue; - - // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet - // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after - // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes - // difference for all packets (http://b/12249687, http:/b/33681750). - // - // Note: this doesn't account for LRO/GRO/GSO/TSO (ie. >mtu) traffic correctly, nor - // does it correctly account for the 8 extra bytes in the IPv6 fragmentation header. - // - // While the ebpf code path does try to simulate proper post segmentation packet - // counts, we have nothing of the sort of xt_qtaguid stats. - entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; - entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; - stackedTraffic.setValues(i, entry); - } - } - - /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. - * - * <p>This mutates the object this method is called on. Equivalent to calling - * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as - * base and stacked traffic. - * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @hide - */ - public void apply464xlatAdjustments(Map<String, String> stackedIfaces) { - apply464xlatAdjustments(this, this, stackedIfaces); - } - - /** - * Return total statistics grouped by {@link #iface}; doesn't mutate the - * original structure. - * @hide - */ - public NetworkStats groupedByIface() { - final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); - - final Entry entry = new Entry(); - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.metered = METERED_ALL; - entry.roaming = ROAMING_ALL; - entry.defaultNetwork = DEFAULT_NETWORK_ALL; - entry.operations = 0L; - - for (int i = 0; i < size; i++) { - // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE) continue; - - entry.iface = iface[i]; - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - stats.combineValues(entry); - } - - return stats; - } - - /** - * Return total statistics grouped by {@link #uid}; doesn't mutate the - * original structure. - * @hide - */ - public NetworkStats groupedByUid() { - final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); - - final Entry entry = new Entry(); - entry.iface = IFACE_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.metered = METERED_ALL; - entry.roaming = ROAMING_ALL; - entry.defaultNetwork = DEFAULT_NETWORK_ALL; - - for (int i = 0; i < size; i++) { - // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE) continue; - - entry.uid = uid[i]; - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - entry.operations = operations[i]; - stats.combineValues(entry); - } - - return stats; - } - - /** - * Remove all rows that match one of specified UIDs. - * This mutates the original structure in place. - * @hide - */ - public void removeUids(int[] uids) { - filter(e -> !CollectionUtils.contains(uids, e.uid)); - } - - /** - * Remove all rows that match one of specified UIDs. - * @return the result object. - * @hide - */ - @NonNull - public NetworkStats removeEmptyEntries() { - final NetworkStats ret = this.clone(); - ret.filter(e -> e.rxBytes != 0 || e.rxPackets != 0 || e.txBytes != 0 || e.txPackets != 0 - || e.operations != 0); - return ret; - } - - /** - * Only keep entries that match all specified filters. - * - * <p>This mutates the original structure in place. After this method is called, - * size is the number of matching entries, and capacity is the previous capacity. - * @param limitUid UID to filter for, or {@link #UID_ALL}. - * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. - * @param limitTag Tag to filter for, or {@link #TAG_ALL}. - * @hide - */ - public void filter(int limitUid, String[] limitIfaces, int limitTag) { - if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { - return; - } - filter(e -> (limitUid == UID_ALL || limitUid == e.uid) - && (limitTag == TAG_ALL || limitTag == e.tag) - && (limitIfaces == INTERFACES_ALL - || CollectionUtils.contains(limitIfaces, e.iface))); - } - - /** - * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. - * - * <p>This mutates the original structure in place. - * @hide - */ - public void filterDebugEntries() { - filter(e -> e.set < SET_DEBUG_START); - } - - private void filter(Predicate<Entry> predicate) { - Entry entry = new Entry(); - int nextOutputEntry = 0; - for (int i = 0; i < size; i++) { - entry = getValues(i, entry); - if (predicate.test(entry)) { - if (nextOutputEntry != i) { - setValues(nextOutputEntry, entry); - } - nextOutputEntry++; - } - } - size = nextOutputEntry; - } - - /** @hide */ - public void dump(String prefix, PrintWriter pw) { - pw.print(prefix); - pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); - for (int i = 0; i < size; i++) { - pw.print(prefix); - pw.print(" ["); pw.print(i); pw.print("]"); - pw.print(" iface="); pw.print(iface[i]); - pw.print(" uid="); pw.print(uid[i]); - pw.print(" set="); pw.print(setToString(set[i])); - pw.print(" tag="); pw.print(tagToString(tag[i])); - pw.print(" metered="); pw.print(meteredToString(metered[i])); - pw.print(" roaming="); pw.print(roamingToString(roaming[i])); - pw.print(" defaultNetwork="); pw.print(defaultNetworkToString(defaultNetwork[i])); - pw.print(" rxBytes="); pw.print(rxBytes[i]); - pw.print(" rxPackets="); pw.print(rxPackets[i]); - pw.print(" txBytes="); pw.print(txBytes[i]); - pw.print(" txPackets="); pw.print(txPackets[i]); - pw.print(" operations="); pw.println(operations[i]); - } - } - - /** - * Return text description of {@link #set} value. - * @hide - */ - public static String setToString(int set) { - switch (set) { - case SET_ALL: - return "ALL"; - case SET_DEFAULT: - return "DEFAULT"; - case SET_FOREGROUND: - return "FOREGROUND"; - case SET_DBG_VPN_IN: - return "DBG_VPN_IN"; - case SET_DBG_VPN_OUT: - return "DBG_VPN_OUT"; - default: - return "UNKNOWN"; - } - } - - /** - * Return text description of {@link #set} value. - * @hide - */ - public static String setToCheckinString(int set) { - switch (set) { - case SET_ALL: - return "all"; - case SET_DEFAULT: - return "def"; - case SET_FOREGROUND: - return "fg"; - case SET_DBG_VPN_IN: - return "vpnin"; - case SET_DBG_VPN_OUT: - return "vpnout"; - default: - return "unk"; - } - } - - /** - * @return true if the querySet matches the dataSet. - * @hide - */ - public static boolean setMatches(int querySet, int dataSet) { - if (querySet == dataSet) { - return true; - } - // SET_ALL matches all non-debugging sets. - return querySet == SET_ALL && dataSet < SET_DEBUG_START; - } - - /** - * Return text description of {@link #tag} value. - * @hide - */ - public static String tagToString(int tag) { - return "0x" + Integer.toHexString(tag); - } - - /** - * Return text description of {@link #metered} value. - * @hide - */ - public static String meteredToString(int metered) { - switch (metered) { - case METERED_ALL: - return "ALL"; - case METERED_NO: - return "NO"; - case METERED_YES: - return "YES"; - default: - return "UNKNOWN"; - } - } - - /** - * Return text description of {@link #roaming} value. - * @hide - */ - public static String roamingToString(int roaming) { - switch (roaming) { - case ROAMING_ALL: - return "ALL"; - case ROAMING_NO: - return "NO"; - case ROAMING_YES: - return "YES"; - default: - return "UNKNOWN"; - } - } - - /** - * Return text description of {@link #defaultNetwork} value. - * @hide - */ - public static String defaultNetworkToString(int defaultNetwork) { - switch (defaultNetwork) { - case DEFAULT_NETWORK_ALL: - return "ALL"; - case DEFAULT_NETWORK_NO: - return "NO"; - case DEFAULT_NETWORK_YES: - return "YES"; - default: - return "UNKNOWN"; - } - } - - /** @hide */ - @Override - public String toString() { - final CharArrayWriter writer = new CharArrayWriter(); - dump("", new PrintWriter(writer)); - return writer.toString(); - } - - @Override - public int describeContents() { - return 0; - } - - public static final @NonNull Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() { - @Override - public NetworkStats createFromParcel(Parcel in) { - return new NetworkStats(in); - } - - @Override - public NetworkStats[] newArray(int size) { - return new NetworkStats[size]; - } - }; - - /** @hide */ - public interface NonMonotonicObserver<C> { - public void foundNonMonotonic( - NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); - public void foundNonMonotonic( - NetworkStats stats, int statsIndex, C cookie); - } - - /** - * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. - * - * <p>This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change - * over time. - * - * <p>This method performs adjustments for one active VPN package and one VPN iface at a time. - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @hide - */ - public void migrateTun(int tunUid, @NonNull String tunIface, - @NonNull List<String> underlyingIfaces) { - // Combined usage by all apps using VPN. - final Entry tunIfaceTotal = new Entry(); - // Usage by VPN, grouped by its {@code underlyingIfaces}. - final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.size()]; - // Usage by VPN, summed across all its {@code underlyingIfaces}. - final Entry underlyingIfacesTotal = new Entry(); - - for (int i = 0; i < perInterfaceTotal.length; i++) { - perInterfaceTotal[i] = new Entry(); - } - - tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, - underlyingIfacesTotal); - - // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. - // Negative stats should be avoided. - final Entry[] moved = - addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, - perInterfaceTotal, underlyingIfacesTotal); - deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); - } - - /** - * Initializes the data used by the migrateTun() method. - * - * <p>This is the first pass iteration which does the following work: - * - * <ul> - * <li>Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and - * background). - * <li>Adds up all the traffic through tun0 excluding traffic from the vpn app itself. - * </ul> - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN - * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code - * underlyingIfaces} - * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its - * {@code underlyingIfaces} - */ - private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, - @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - final Entry recycle = new Entry(); - for (int i = 0; i < size; i++) { - getValues(i, recycle); - if (recycle.uid == UID_ALL) { - throw new IllegalStateException( - "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } - if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { - throw new IllegalStateException( - "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); - } - if (recycle.tag != TAG_NONE) { - // TODO(b/123666283): Take all tags for tunUid into account. - continue; - } - - if (tunUid == Process.SYSTEM_UID) { - // Kernel-based VPN or VCN, traffic sent by apps on the VPN/VCN network - // - // Since the data is not UID-accounted on underlying networks, just use VPN/VCN - // network usage as ground truth. Encrypted traffic on the underlying networks will - // never be processed here because encrypted traffic on the underlying interfaces - // is not present in UID stats, and this method is only called on UID stats. - if (tunIface.equals(recycle.iface)) { - tunIfaceTotal.add(recycle); - underlyingIfacesTotal.add(recycle); - - // In steady state, there should always be one network, but edge cases may - // result in the network being null (network lost), and thus no underlying - // ifaces is possible. - if (perInterfaceTotal.length > 0) { - // While platform VPNs and VCNs have exactly one underlying network, that - // network may have multiple interfaces (eg for 464xlat). This layer does - // not have the required information to identify which of the interfaces - // were used. Select "any" of the interfaces. Since overhead is already - // lost, this number is an approximation anyways. - perInterfaceTotal[0].add(recycle); - } - } - } else if (recycle.uid == tunUid) { - // VpnService VPN, traffic sent by the VPN app over underlying networks - for (int j = 0; j < underlyingIfaces.size(); j++) { - if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) { - perInterfaceTotal[j].add(recycle); - underlyingIfacesTotal.add(recycle); - break; - } - } - } else if (tunIface.equals(recycle.iface)) { - // VpnService VPN; traffic sent by apps on the VPN network - tunIfaceTotal.add(recycle); - } - } - } - - /** - * Distributes traffic across apps that are using given {@code tunIface}, and returns the total - * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} - * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} - * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code - * underlyingIfaces} - */ - private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, - @NonNull List<String> underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - // Traffic that should be moved off of each underlying interface for tunUid (see - // deductTrafficFromVpnApp below). - final Entry[] moved = new Entry[underlyingIfaces.size()]; - for (int i = 0; i < underlyingIfaces.size(); i++) { - moved[i] = new Entry(); - } - - final Entry tmpEntry = new Entry(); - final int origSize = size; - for (int i = 0; i < origSize; i++) { - if (!Objects.equals(iface[i], tunIface)) { - // Consider only entries that go onto the VPN interface. - continue; - } - - if (uid[i] == tunUid && tunUid != Process.SYSTEM_UID) { - // Exclude VPN app from the redistribution, as it can choose to create packet - // streams by writing to itself. - // - // However, for platform VPNs, do not exclude the system's usage of the VPN network, - // since it is never local-only, and never double counted - continue; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; - - // In a first pass, compute this entry's total share of data across all - // underlyingIfaces. This is computed on the basis of the share of this entry's usage - // over tunIface. - // TODO: Consider refactoring first pass into a separate helper method. - long totalRxBytes = 0; - if (tunIfaceTotal.rxBytes > 0) { - // Note - The multiplication below should not overflow since NetworkStatsService - // processes this every time device has transmitted/received amount equivalent to - // global threshold alert (~ 2MB) across all interfaces. - final long rxBytesAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.rxBytes, - rxBytes[i], tunIfaceTotal.rxBytes); - // app must not be blamed for more than it consumed on tunIface - totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); - } - long totalRxPackets = 0; - if (tunIfaceTotal.rxPackets > 0) { - final long rxPacketsAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.rxPackets, - rxPackets[i], tunIfaceTotal.rxPackets); - totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); - } - long totalTxBytes = 0; - if (tunIfaceTotal.txBytes > 0) { - final long txBytesAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.txBytes, - txBytes[i], tunIfaceTotal.txBytes); - totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); - } - long totalTxPackets = 0; - if (tunIfaceTotal.txPackets > 0) { - final long txPacketsAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.txPackets, - txPackets[i], tunIfaceTotal.txPackets); - totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); - } - long totalOperations = 0; - if (tunIfaceTotal.operations > 0) { - final long operationsAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.operations, - operations[i], tunIfaceTotal.operations); - totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); - } - // In a second pass, distribute these values across interfaces in the proportion that - // each interface represents of the total traffic of the underlying interfaces. - for (int j = 0; j < underlyingIfaces.size(); j++) { - tmpEntry.iface = underlyingIfaces.get(j); - tmpEntry.rxBytes = 0; - // Reset 'set' to correct value since it gets updated when adding debug info below. - tmpEntry.set = set[i]; - if (underlyingIfacesTotal.rxBytes > 0) { - tmpEntry.rxBytes = - multiplySafeByRational(totalRxBytes, - perInterfaceTotal[j].rxBytes, - underlyingIfacesTotal.rxBytes); - } - tmpEntry.rxPackets = 0; - if (underlyingIfacesTotal.rxPackets > 0) { - tmpEntry.rxPackets = - multiplySafeByRational(totalRxPackets, - perInterfaceTotal[j].rxPackets, - underlyingIfacesTotal.rxPackets); - } - tmpEntry.txBytes = 0; - if (underlyingIfacesTotal.txBytes > 0) { - tmpEntry.txBytes = - multiplySafeByRational(totalTxBytes, - perInterfaceTotal[j].txBytes, - underlyingIfacesTotal.txBytes); - } - tmpEntry.txPackets = 0; - if (underlyingIfacesTotal.txPackets > 0) { - tmpEntry.txPackets = - multiplySafeByRational(totalTxPackets, - perInterfaceTotal[j].txPackets, - underlyingIfacesTotal.txPackets); - } - tmpEntry.operations = 0; - if (underlyingIfacesTotal.operations > 0) { - tmpEntry.operations = - multiplySafeByRational(totalOperations, - perInterfaceTotal[j].operations, - underlyingIfacesTotal.operations); - } - // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying - // interface. Add that data usage to this object. - combineValues(tmpEntry); - if (tag[i] == TAG_NONE) { - // Add the migrated data to moved so it is deducted from the VPN app later. - moved[j].add(tmpEntry); - // Add debug info - tmpEntry.set = SET_DBG_VPN_IN; - combineValues(tmpEntry); - } - } - } - return moved; - } - - private void deductTrafficFromVpnApp( - int tunUid, - @NonNull List<String> underlyingIfaces, - @NonNull Entry[] moved) { - if (tunUid == Process.SYSTEM_UID) { - // No traffic recorded on a per-UID basis for in-kernel VPN/VCNs over underlying - // networks; thus no traffic to deduct. - return; - } - - for (int i = 0; i < underlyingIfaces.size(); i++) { - moved[i].uid = tunUid; - // Add debug info - moved[i].set = SET_DBG_VPN_OUT; - moved[i].tag = TAG_NONE; - moved[i].iface = underlyingIfaces.get(i); - moved[i].metered = METERED_ALL; - moved[i].roaming = ROAMING_ALL; - moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved[i]); - - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and - // METERED_NO, which should be the case as it comes directly from the /proc file. - // We only blend in the roaming data after applying these adjustments, by checking the - // NetworkIdentity of the underlying iface. - final int idxVpnBackground = findIndex(underlyingIfaces.get(i), tunUid, SET_DEFAULT, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed - // from foreground usage. - tunSubtract(idxVpnBackground, this, moved[i]); - } - - final int idxVpnForeground = findIndex(underlyingIfaces.get(i), tunUid, SET_FOREGROUND, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved[i]); - } - } - } - - private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { - long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); - left.rxBytes[i] -= rxBytes; - right.rxBytes -= rxBytes; - - long rxPackets = Math.min(left.rxPackets[i], right.rxPackets); - left.rxPackets[i] -= rxPackets; - right.rxPackets -= rxPackets; - - long txBytes = Math.min(left.txBytes[i], right.txBytes); - left.txBytes[i] -= txBytes; - right.txBytes -= txBytes; - - long txPackets = Math.min(left.txPackets[i], right.txPackets); - left.txPackets[i] -= txPackets; - right.txPackets -= txPackets; - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java deleted file mode 100644 index b64fbdba9a01..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.UID_REMOVED; -import static android.net.TrafficStats.UID_TETHERING; - -import android.Manifest; -import android.annotation.IntDef; -import android.app.AppOpsManager; -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.Process; -import android.os.UserHandle; -import android.telephony.TelephonyManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Utility methods for controlling access to network stats APIs. - * - * @hide - */ -public final class NetworkStatsAccess { - private NetworkStatsAccess() {} - - /** - * Represents an access level for the network usage history and statistics APIs. - * - * <p>Access levels are in increasing order; that is, it is reasonable to check access by - * verifying that the caller's access level is at least the minimum required level. - */ - @IntDef({ - Level.DEFAULT, - Level.USER, - Level.DEVICESUMMARY, - Level.DEVICE, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Level { - /** - * Default, unprivileged access level. - * - * <p>Can only access usage for one's own UID. - * - * <p>Every app will have at least this access level. - */ - int DEFAULT = 0; - - /** - * Access level for apps which can access usage for any app running in the same user. - * - * <p>Granted to: - * <ul> - * <li>Profile owners. - * </ul> - */ - int USER = 1; - - /** - * Access level for apps which can access usage summary of device. Device summary includes - * usage by apps running in any profiles/users, however this access level does not - * allow querying usage of individual apps running in other profiles/users. - * - * <p>Granted to: - * <ul> - * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit - * so it is not necessarily sufficient to declare this in the manifest. - * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. - * </ul> - */ - int DEVICESUMMARY = 2; - - /** - * Access level for apps which can access usage for any app on the device, including apps - * running on other users/profiles. - * - * <p>Granted to: - * <ul> - * <li>Device owners. - * <li>Carrier-privileged applications. - * <li>The system UID. - * </ul> - */ - int DEVICE = 3; - } - - /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ - public static @NetworkStatsAccess.Level int checkAccessLevel( - Context context, int callingPid, int callingUid, String callingPackage) { - final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class); - final TelephonyManager tm = (TelephonyManager) - context.getSystemService(Context.TELEPHONY_SERVICE); - boolean hasCarrierPrivileges; - final long token = Binder.clearCallingIdentity(); - try { - hasCarrierPrivileges = tm != null - && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; - } finally { - Binder.restoreCallingIdentity(token); - } - - final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); - final int appId = UserHandle.getAppId(callingUid); - - final boolean isNetworkStack = context.checkPermission( - android.Manifest.permission.NETWORK_STACK, callingPid, callingUid) - == PERMISSION_GRANTED; - - if (hasCarrierPrivileges || isDeviceOwner - || appId == Process.SYSTEM_UID || isNetworkStack) { - // Carrier-privileged apps and device owners, and the system (including the - // network stack) can access data usage for all apps on the device. - return NetworkStatsAccess.Level.DEVICE; - } - - boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage); - if (hasAppOpsPermission || context.checkCallingOrSelfPermission( - READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) { - return NetworkStatsAccess.Level.DEVICESUMMARY; - } - - //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. - boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage) - || mDpm.isDeviceOwnerApp(callingPackage)); - if (isProfileOwner) { - // Apps with the AppOps permission, profile owners, and apps with the privileged - // permission can access data usage for all apps in this user/profile. - return NetworkStatsAccess.Level.USER; - } - - // Everyone else gets default access (only to their own UID). - return NetworkStatsAccess.Level.DEFAULT; - } - - /** - * Returns whether the given caller should be able to access the given UID when the caller has - * the given {@link NetworkStatsAccess.Level}. - */ - public static boolean isAccessibleToUser(int uid, int callerUid, - @NetworkStatsAccess.Level int accessLevel) { - final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); - final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier(); - switch (accessLevel) { - case NetworkStatsAccess.Level.DEVICE: - // Device-level access - can access usage for any uid. - return true; - case NetworkStatsAccess.Level.DEVICESUMMARY: - // Can access usage for any app running in the same user, along - // with some special uids (system, removed, or tethering) and - // anonymized uids - return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED - || uid == UID_TETHERING || uid == UID_ALL - || userId == callerUserId; - case NetworkStatsAccess.Level.USER: - // User-level access - can access usage for any app running in the same user, along - // with some special uids (system, removed, or tethering). - return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED - || uid == UID_TETHERING - || userId == callerUserId; - case NetworkStatsAccess.Level.DEFAULT: - default: - // Default access level - can only access one's own usage. - return uid == callerUid; - } - } - - private static boolean hasAppOpsPermission( - Context context, int callingUid, String callingPackage) { - if (callingPackage != null) { - AppOpsManager appOps = (AppOpsManager) context.getSystemService( - Context.APP_OPS_SERVICE); - - final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS, - callingUid, callingPackage, null /* attributionTag */, null /* message */); - if (mode == AppOpsManager.MODE_DEFAULT) { - // The default behavior here is to check if PackageManager has given the app - // permission. - final int permissionCheck = context.checkCallingPermission( - Manifest.permission.PACKAGE_USAGE_STATS); - return permissionCheck == PackageManager.PERMISSION_GRANTED; - } - return (mode == AppOpsManager.MODE_ALLOWED); - } - return false; - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java deleted file mode 100644 index e385b33447f0..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java +++ /dev/null @@ -1,956 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkStats.DEFAULT_NETWORK_NO; -import static android.net.NetworkStats.DEFAULT_NETWORK_YES; -import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.METERED_NO; -import static android.net.NetworkStats.METERED_YES; -import static android.net.NetworkStats.ROAMING_NO; -import static android.net.NetworkStats.ROAMING_YES; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.UID_REMOVED; -import static android.text.format.DateUtils.WEEK_IN_MILLIS; - -import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.net.NetworkStats.State; -import android.net.NetworkStatsHistory.Entry; -import android.os.Binder; -import android.service.NetworkStatsCollectionKeyProto; -import android.service.NetworkStatsCollectionProto; -import android.service.NetworkStatsCollectionStatsProto; -import android.telephony.SubscriptionPlan; -import android.text.format.DateUtils; -import android.util.ArrayMap; -import android.util.AtomicFile; -import android.util.IndentingPrintWriter; -import android.util.Log; -import android.util.Range; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.FileRotator; -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkStatsUtils; - -import libcore.io.IoUtils; - -import java.io.BufferedInputStream; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.net.ProtocolException; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * Collection of {@link NetworkStatsHistory}, stored based on combined key of - * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer { - private static final String TAG = NetworkStatsCollection.class.getSimpleName(); - /** File header magic number: "ANET" */ - private static final int FILE_MAGIC = 0x414E4554; - - private static final int VERSION_NETWORK_INIT = 1; - - private static final int VERSION_UID_INIT = 1; - private static final int VERSION_UID_WITH_IDENT = 2; - private static final int VERSION_UID_WITH_TAG = 3; - private static final int VERSION_UID_WITH_SET = 4; - - private static final int VERSION_UNIFIED_INIT = 16; - - private ArrayMap<Key, NetworkStatsHistory> mStats = new ArrayMap<>(); - - private final long mBucketDurationMillis; - - private long mStartMillis; - private long mEndMillis; - private long mTotalBytes; - private boolean mDirty; - - /** - * Construct a {@link NetworkStatsCollection} object. - * - * @param bucketDuration duration of the buckets in this object, in milliseconds. - * @hide - */ - public NetworkStatsCollection(long bucketDurationMillis) { - mBucketDurationMillis = bucketDurationMillis; - reset(); - } - - /** @hide */ - public void clear() { - reset(); - } - - /** @hide */ - public void reset() { - mStats.clear(); - mStartMillis = Long.MAX_VALUE; - mEndMillis = Long.MIN_VALUE; - mTotalBytes = 0; - mDirty = false; - } - - /** @hide */ - public long getStartMillis() { - return mStartMillis; - } - - /** - * Return first atomic bucket in this collection, which is more conservative - * than {@link #mStartMillis}. - * @hide - */ - public long getFirstAtomicBucketMillis() { - if (mStartMillis == Long.MAX_VALUE) { - return Long.MAX_VALUE; - } else { - return mStartMillis + mBucketDurationMillis; - } - } - - /** @hide */ - public long getEndMillis() { - return mEndMillis; - } - - /** @hide */ - public long getTotalBytes() { - return mTotalBytes; - } - - /** @hide */ - public boolean isDirty() { - return mDirty; - } - - /** @hide */ - public void clearDirty() { - mDirty = false; - } - - /** @hide */ - public boolean isEmpty() { - return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; - } - - /** @hide */ - @VisibleForTesting - public long roundUp(long time) { - if (time == Long.MIN_VALUE || time == Long.MAX_VALUE - || time == SubscriptionPlan.TIME_UNKNOWN) { - return time; - } else { - final long mod = time % mBucketDurationMillis; - if (mod > 0) { - time -= mod; - time += mBucketDurationMillis; - } - return time; - } - } - - /** @hide */ - @VisibleForTesting - public long roundDown(long time) { - if (time == Long.MIN_VALUE || time == Long.MAX_VALUE - || time == SubscriptionPlan.TIME_UNKNOWN) { - return time; - } else { - final long mod = time % mBucketDurationMillis; - if (mod > 0) { - time -= mod; - } - return time; - } - } - - /** @hide */ - public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { - return getRelevantUids(accessLevel, Binder.getCallingUid()); - } - - /** @hide */ - public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, - final int callerUid) { - final ArrayList<Integer> uids = new ArrayList<>(); - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) { - int j = Collections.binarySearch(uids, new Integer(key.uid)); - - if (j < 0) { - j = ~j; - uids.add(j, key.uid); - } - } - } - return CollectionUtils.toIntArray(uids); - } - - /** - * Combine all {@link NetworkStatsHistory} in this collection which match - * the requested parameters. - * @hide - */ - public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan, - int uid, int set, int tag, int fields, long start, long end, - @NetworkStatsAccess.Level int accessLevel, int callerUid) { - if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { - throw new SecurityException("Network stats history of uid " + uid - + " is forbidden for caller " + callerUid); - } - - // 180 days of history should be enough for anyone; if we end up needing - // more, we'll dynamically grow the history object. - final int bucketEstimate = (int) NetworkStatsUtils.constrain( - ((end - start) / mBucketDurationMillis), 0, - (180 * DateUtils.DAY_IN_MILLIS) / mBucketDurationMillis); - final NetworkStatsHistory combined = new NetworkStatsHistory( - mBucketDurationMillis, bucketEstimate, fields); - - // shortcut when we know stats will be empty - if (start == end) return combined; - - // Figure out the window of time that we should be augmenting (if any) - long augmentStart = SubscriptionPlan.TIME_UNKNOWN; - long augmentEnd = (augmentPlan != null) ? augmentPlan.getDataUsageTime() - : SubscriptionPlan.TIME_UNKNOWN; - // And if augmenting, we might need to collect more data to adjust with - long collectStart = start; - long collectEnd = end; - - if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) { - final Iterator<Range<ZonedDateTime>> it = augmentPlan.cycleIterator(); - while (it.hasNext()) { - final Range<ZonedDateTime> cycle = it.next(); - final long cycleStart = cycle.getLower().toInstant().toEpochMilli(); - final long cycleEnd = cycle.getUpper().toInstant().toEpochMilli(); - if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) { - augmentStart = cycleStart; - collectStart = Long.min(collectStart, augmentStart); - collectEnd = Long.max(collectEnd, augmentEnd); - break; - } - } - } - - if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { - // Shrink augmentation window so we don't risk undercounting. - augmentStart = roundUp(augmentStart); - augmentEnd = roundDown(augmentEnd); - // Grow collection window so we get all the stats needed. - collectStart = roundDown(collectStart); - collectEnd = roundUp(collectEnd); - } - - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag - && templateMatches(template, key.ident)) { - final NetworkStatsHistory value = mStats.valueAt(i); - combined.recordHistory(value, collectStart, collectEnd); - } - } - - if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { - final NetworkStatsHistory.Entry entry = combined.getValues( - augmentStart, augmentEnd, null); - - // If we don't have any recorded data for this time period, give - // ourselves something to scale with. - if (entry.rxBytes == 0 || entry.txBytes == 0) { - combined.recordData(augmentStart, augmentEnd, - new NetworkStats.Entry(1, 0, 1, 0, 0)); - combined.getValues(augmentStart, augmentEnd, entry); - } - - final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 : - (entry.rxBytes + entry.txBytes); - final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes; - final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes; - final long targetBytes = augmentPlan.getDataUsageBytes(); - - final long targetRxBytes = multiplySafeByRational(targetBytes, rawRxBytes, rawBytes); - final long targetTxBytes = multiplySafeByRational(targetBytes, rawTxBytes, rawBytes); - - - // Scale all matching buckets to reach anchor target - final long beforeTotal = combined.getTotalBytes(); - for (int i = 0; i < combined.size(); i++) { - combined.getValues(i, entry); - if (entry.bucketStart >= augmentStart - && entry.bucketStart + entry.bucketDuration <= augmentEnd) { - entry.rxBytes = multiplySafeByRational( - targetRxBytes, entry.rxBytes, rawRxBytes); - entry.txBytes = multiplySafeByRational( - targetTxBytes, entry.txBytes, rawTxBytes); - // We purposefully clear out packet counters to indicate - // that this data has been augmented. - entry.rxPackets = 0; - entry.txPackets = 0; - combined.setValues(i, entry); - } - } - - final long deltaTotal = combined.getTotalBytes() - beforeTotal; - if (deltaTotal != 0) { - Log.d(TAG, "Augmented network usage by " + deltaTotal + " bytes"); - } - - // Finally we can slice data as originally requested - final NetworkStatsHistory sliced = new NetworkStatsHistory( - mBucketDurationMillis, bucketEstimate, fields); - sliced.recordHistory(combined, start, end); - return sliced; - } else { - return combined; - } - } - - /** - * Summarize all {@link NetworkStatsHistory} in this collection which match - * the requested parameters across the requested range. - * - * @param template - a predicate for filtering netstats. - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param accessLevel - caller access level. - * @param callerUid - caller UID. - * @hide - */ - public NetworkStats getSummary(NetworkTemplate template, long start, long end, - @NetworkStatsAccess.Level int accessLevel, int callerUid) { - final long now = System.currentTimeMillis(); - - final NetworkStats stats = new NetworkStats(end - start, 24); - - // shortcut when we know stats will be empty - if (start == end) return stats; - - final NetworkStats.Entry entry = new NetworkStats.Entry(); - NetworkStatsHistory.Entry historyEntry = null; - - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - if (templateMatches(template, key.ident) - && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel) - && key.set < NetworkStats.SET_DEBUG_START) { - final NetworkStatsHistory value = mStats.valueAt(i); - historyEntry = value.getValues(start, end, now, historyEntry); - - entry.iface = IFACE_ALL; - entry.uid = key.uid; - entry.set = key.set; - entry.tag = key.tag; - entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() - ? DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO; - entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; - entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; - entry.rxBytes = historyEntry.rxBytes; - entry.rxPackets = historyEntry.rxPackets; - entry.txBytes = historyEntry.txBytes; - entry.txPackets = historyEntry.txPackets; - entry.operations = historyEntry.operations; - - if (!entry.isEmpty()) { - stats.combineValues(entry); - } - } - } - - return stats; - } - - /** - * Record given {@link android.net.NetworkStats.Entry} into this collection. - * @hide - */ - public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, - long end, NetworkStats.Entry entry) { - final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag); - history.recordData(start, end, entry); - noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes); - } - - /** - * Record given {@link NetworkStatsHistory} into this collection. - * - * @hide - */ - public void recordHistory(@NonNull Key key, @NonNull NetworkStatsHistory history) { - Objects.requireNonNull(key); - Objects.requireNonNull(history); - if (history.size() == 0) return; - noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes()); - - NetworkStatsHistory target = mStats.get(key); - if (target == null) { - target = new NetworkStatsHistory(history.getBucketDuration()); - mStats.put(key, target); - } - target.recordEntireHistory(history); - } - - /** - * Record all {@link NetworkStatsHistory} contained in the given collection - * into this collection. - * - * @hide - */ - public void recordCollection(@NonNull NetworkStatsCollection another) { - Objects.requireNonNull(another); - for (int i = 0; i < another.mStats.size(); i++) { - final Key key = another.mStats.keyAt(i); - final NetworkStatsHistory value = another.mStats.valueAt(i); - recordHistory(key, value); - } - } - - private NetworkStatsHistory findOrCreateHistory( - NetworkIdentitySet ident, int uid, int set, int tag) { - final Key key = new Key(ident, uid, set, tag); - final NetworkStatsHistory existing = mStats.get(key); - - // update when no existing, or when bucket duration changed - NetworkStatsHistory updated = null; - if (existing == null) { - updated = new NetworkStatsHistory(mBucketDurationMillis, 10); - } else if (existing.getBucketDuration() != mBucketDurationMillis) { - updated = new NetworkStatsHistory(existing, mBucketDurationMillis); - } - - if (updated != null) { - mStats.put(key, updated); - return updated; - } else { - return existing; - } - } - - /** @hide */ - @Override - public void read(InputStream in) throws IOException { - read((DataInput) new DataInputStream(in)); - } - - private void read(DataInput in) throws IOException { - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_UNIFIED_INIT: { - // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) - final int identSize = in.readInt(); - for (int i = 0; i < identSize; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - - final int size = in.readInt(); - for (int j = 0; j < size; j++) { - final int uid = in.readInt(); - final int set = in.readInt(); - final int tag = in.readInt(); - - final Key key = new Key(ident, uid, set, tag); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - recordHistory(key, history); - } - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } - - /** @hide */ - @Override - public void write(OutputStream out) throws IOException { - write((DataOutput) new DataOutputStream(out)); - out.flush(); - } - - private void write(DataOutput out) throws IOException { - // cluster key lists grouped by ident - final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = new HashMap<>(); - for (Key key : mStats.keySet()) { - ArrayList<Key> keys = keysByIdent.get(key.ident); - if (keys == null) { - keys = new ArrayList<>(); - keysByIdent.put(key.ident, keys); - } - keys.add(key); - } - - out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_UNIFIED_INIT); - - out.writeInt(keysByIdent.size()); - for (NetworkIdentitySet ident : keysByIdent.keySet()) { - final ArrayList<Key> keys = keysByIdent.get(ident); - ident.writeToStream(out); - - out.writeInt(keys.size()); - for (Key key : keys) { - final NetworkStatsHistory history = mStats.get(key); - out.writeInt(key.uid); - out.writeInt(key.set); - out.writeInt(key.tag); - history.writeToStream(out); - } - } - } - - /** - * Read legacy network summary statistics file format into the collection, - * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. - * - * @deprecated - * @hide - */ - @Deprecated - public void readLegacyNetwork(File file) throws IOException { - final AtomicFile inputFile = new AtomicFile(file); - - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); - - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_NETWORK_INIT: { - // network := size *(NetworkIdentitySet NetworkStatsHistory) - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - - final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE); - recordHistory(key, history); - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } catch (FileNotFoundException e) { - // missing stats is okay, probably first boot - } finally { - IoUtils.closeQuietly(in); - } - } - - /** - * Read legacy Uid statistics file format into the collection, - * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. - * - * @deprecated - * @hide - */ - @Deprecated - public void readLegacyUid(File file, boolean onlyTags) throws IOException { - final AtomicFile inputFile = new AtomicFile(file); - - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); - - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_UID_INIT: { - // uid := size *(UID NetworkStatsHistory) - - // drop this data version, since we don't have a good - // mapping into NetworkIdentitySet. - break; - } - case VERSION_UID_WITH_IDENT: { - // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) - - // drop this data version, since this version only existed - // for a short time. - break; - } - case VERSION_UID_WITH_TAG: - case VERSION_UID_WITH_SET: { - // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) - final int identSize = in.readInt(); - for (int i = 0; i < identSize; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - - final int size = in.readInt(); - for (int j = 0; j < size; j++) { - final int uid = in.readInt(); - final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() - : SET_DEFAULT; - final int tag = in.readInt(); - - final Key key = new Key(ident, uid, set, tag); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - - if ((tag == TAG_NONE) != onlyTags) { - recordHistory(key, history); - } - } - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } catch (FileNotFoundException e) { - // missing stats is okay, probably first boot - } finally { - IoUtils.closeQuietly(in); - } - } - - /** - * Remove any {@link NetworkStatsHistory} attributed to the requested UID, - * moving any {@link NetworkStats#TAG_NONE} series to - * {@link TrafficStats#UID_REMOVED}. - * @hide - */ - public void removeUids(int[] uids) { - final ArrayList<Key> knownKeys = new ArrayList<>(); - knownKeys.addAll(mStats.keySet()); - - // migrate all UID stats into special "removed" bucket - for (Key key : knownKeys) { - if (CollectionUtils.contains(uids, key.uid)) { - // only migrate combined TAG_NONE history - if (key.tag == TAG_NONE) { - final NetworkStatsHistory uidHistory = mStats.get(key); - final NetworkStatsHistory removedHistory = findOrCreateHistory( - key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE); - removedHistory.recordEntireHistory(uidHistory); - } - mStats.remove(key); - mDirty = true; - } - } - } - - private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) { - if (startMillis < mStartMillis) mStartMillis = startMillis; - if (endMillis > mEndMillis) mEndMillis = endMillis; - mTotalBytes += totalBytes; - mDirty = true; - } - - private int estimateBuckets() { - return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5) - / mBucketDurationMillis); - } - - private ArrayList<Key> getSortedKeys() { - final ArrayList<Key> keys = new ArrayList<>(); - keys.addAll(mStats.keySet()); - Collections.sort(keys, (left, right) -> Key.compare(left, right)); - return keys; - } - - /** @hide */ - public void dump(IndentingPrintWriter pw) { - for (Key key : getSortedKeys()) { - pw.print("ident="); pw.print(key.ident.toString()); - pw.print(" uid="); pw.print(key.uid); - pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); - pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag)); - - final NetworkStatsHistory history = mStats.get(key); - pw.increaseIndent(); - history.dump(pw, true); - pw.decreaseIndent(); - } - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS); - - // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); - proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); - proto.end(startKey); - - // Value - final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); - proto.end(startStats); - } - - proto.end(start); - } - - /** @hide */ - public void dumpCheckin(PrintWriter pw, long start, long end) { - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth"); - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt"); - } - - /** - * Dump all contained stats that match requested parameters, but group - * together all matching {@link NetworkTemplate} under a single prefix. - */ - private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate, - String groupPrefix) { - final ArrayMap<Key, NetworkStatsHistory> grouped = new ArrayMap<>(); - - // Walk through all history, grouping by matching network templates - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - final NetworkStatsHistory value = mStats.valueAt(i); - - if (!templateMatches(groupTemplate, key.ident)) continue; - if (key.set >= NetworkStats.SET_DEBUG_START) continue; - - final Key groupKey = new Key(null, key.uid, key.set, key.tag); - NetworkStatsHistory groupHistory = grouped.get(groupKey); - if (groupHistory == null) { - groupHistory = new NetworkStatsHistory(value.getBucketDuration()); - grouped.put(groupKey, groupHistory); - } - groupHistory.recordHistory(value, start, end); - } - - for (int i = 0; i < grouped.size(); i++) { - final Key key = grouped.keyAt(i); - final NetworkStatsHistory value = grouped.valueAt(i); - - if (value.size() == 0) continue; - - pw.print("c,"); - pw.print(groupPrefix); pw.print(','); - pw.print(key.uid); pw.print(','); - pw.print(NetworkStats.setToCheckinString(key.set)); pw.print(','); - pw.print(key.tag); - pw.println(); - - value.dumpCheckin(pw); - } - } - - /** - * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} - * in the given {@link NetworkIdentitySet}. - */ - private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { - for (NetworkIdentity ident : identSet) { - if (template.matches(ident)) { - return true; - } - } - return false; - } - - /** - * Get the all historical stats of the collection {@link NetworkStatsCollection}. - * - * @return All {@link NetworkStatsHistory} in this collection. - */ - @NonNull - public Map<Key, NetworkStatsHistory> getEntries() { - return new ArrayMap(mStats); - } - - /** - * Builder class for {@link NetworkStatsCollection}. - */ - public static final class Builder { - private final long mBucketDurationMillis; - private final ArrayMap<Key, NetworkStatsHistory> mEntries = new ArrayMap<>(); - - /** - * Creates a new Builder with given bucket duration. - * - * @param bucketDuration Duration of the buckets of the object, in milliseconds. - */ - public Builder(long bucketDurationMillis) { - mBucketDurationMillis = bucketDurationMillis; - } - - /** - * Add association of the history with the specified key in this map. - * - * @param key The object used to identify a network, see {@link Key}. - * @param history {@link NetworkStatsHistory} instance associated to the given {@link Key}. - * @return The builder object. - */ - @NonNull - public NetworkStatsCollection.Builder addEntry(@NonNull Key key, - @NonNull NetworkStatsHistory history) { - Objects.requireNonNull(key); - Objects.requireNonNull(history); - final List<Entry> historyEntries = history.getEntries(); - - final NetworkStatsHistory.Builder historyBuilder = - new NetworkStatsHistory.Builder(mBucketDurationMillis, historyEntries.size()); - for (Entry entry : historyEntries) { - historyBuilder.addEntry(entry); - } - - mEntries.put(key, historyBuilder.build()); - return this; - } - - /** - * Builds the instance of the {@link NetworkStatsCollection}. - * - * @return the built instance of {@link NetworkStatsCollection}. - */ - @NonNull - public NetworkStatsCollection build() { - final NetworkStatsCollection collection = - new NetworkStatsCollection(mBucketDurationMillis); - for (int i = 0; i < mEntries.size(); i++) { - collection.recordHistory(mEntries.keyAt(i), mEntries.valueAt(i)); - } - return collection; - } - } - - /** - * the identifier that associate with the {@link NetworkStatsHistory} object to identify - * a certain record in the {@link NetworkStatsCollection} object. - */ - public static final class Key { - /** @hide */ - public final NetworkIdentitySet ident; - /** @hide */ - public final int uid; - /** @hide */ - public final int set; - /** @hide */ - public final int tag; - - private final int mHashCode; - - /** - * Construct a {@link Key} object. - * - * @param ident a Set of {@link NetworkIdentity} that associated with the record. - * @param uid Uid of the record. - * @param set Set of the record, see {@code NetworkStats#SET_*}. - * @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}. - */ - public Key(@NonNull Set<NetworkIdentity> ident, int uid, @State int set, int tag) { - this(new NetworkIdentitySet(Objects.requireNonNull(ident)), uid, set, tag); - } - - /** @hide */ - public Key(@NonNull NetworkIdentitySet ident, int uid, int set, int tag) { - this.ident = Objects.requireNonNull(ident); - this.uid = uid; - this.set = set; - this.tag = tag; - mHashCode = Objects.hash(ident, uid, set, tag); - } - - @Override - public int hashCode() { - return mHashCode; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof Key) { - final Key key = (Key) obj; - return uid == key.uid && set == key.set && tag == key.tag - && Objects.equals(ident, key.ident); - } - return false; - } - - /** @hide */ - public static int compare(@NonNull Key left, @NonNull Key right) { - Objects.requireNonNull(left); - Objects.requireNonNull(right); - int res = 0; - if (left.ident != null && right.ident != null) { - res = NetworkIdentitySet.compare(left.ident, right.ident); - } - if (res == 0) { - res = Integer.compare(left.uid, right.uid); - } - if (res == 0) { - res = Integer.compare(left.set, right.set); - } - if (res == 0) { - res = Integer.compare(left.tag, right.tag); - } - return res; - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java deleted file mode 100644 index 301fef944169..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray; -import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray; -import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; -import static android.net.NetworkStatsHistory.Entry.UNKNOWN; -import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; -import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; - -import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.service.NetworkStatsHistoryBucketProto; -import android.service.NetworkStatsHistoryProto; -import android.util.IndentingPrintWriter; -import android.util.proto.ProtoOutputStream; - -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkStatsUtils; - -import libcore.util.EmptyArray; - -import java.io.CharArrayWriter; -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.ProtocolException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -/** - * Collection of historical network statistics, recorded into equally-sized - * "buckets" in time. Internally it stores data in {@code long} series for more - * efficient persistence. - * <p> - * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for - * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is - * sorted at all times. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class NetworkStatsHistory implements Parcelable { - private static final int VERSION_INIT = 1; - private static final int VERSION_ADD_PACKETS = 2; - private static final int VERSION_ADD_ACTIVE = 3; - - /** @hide */ - public static final int FIELD_ACTIVE_TIME = 0x01; - /** @hide */ - public static final int FIELD_RX_BYTES = 0x02; - /** @hide */ - public static final int FIELD_RX_PACKETS = 0x04; - /** @hide */ - public static final int FIELD_TX_BYTES = 0x08; - /** @hide */ - public static final int FIELD_TX_PACKETS = 0x10; - /** @hide */ - public static final int FIELD_OPERATIONS = 0x20; - /** @hide */ - public static final int FIELD_ALL = 0xFFFFFFFF; - - private long bucketDuration; - private int bucketCount; - private long[] bucketStart; - private long[] activeTime; - private long[] rxBytes; - private long[] rxPackets; - private long[] txBytes; - private long[] txPackets; - private long[] operations; - private long totalBytes; - - /** @hide */ - public NetworkStatsHistory(long bucketDuration, long[] bucketStart, long[] activeTime, - long[] rxBytes, long[] rxPackets, long[] txBytes, long[] txPackets, - long[] operations, int bucketCount, long totalBytes) { - this.bucketDuration = bucketDuration; - this.bucketStart = bucketStart; - this.activeTime = activeTime; - this.rxBytes = rxBytes; - this.rxPackets = rxPackets; - this.txBytes = txBytes; - this.txPackets = txPackets; - this.operations = operations; - this.bucketCount = bucketCount; - this.totalBytes = totalBytes; - } - - /** - * An instance to represent a single record in a {@link NetworkStatsHistory} object. - */ - public static final class Entry { - /** @hide */ - public static final long UNKNOWN = -1; - - /** @hide */ - // TODO: Migrate all callers to get duration from the history object and remove this field. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long bucketDuration; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long bucketStart; - /** @hide */ - public long activeTime; - /** @hide */ - @UnsupportedAppUsage - public long rxBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long rxPackets; - /** @hide */ - @UnsupportedAppUsage - public long txBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long txPackets; - /** @hide */ - public long operations; - /** @hide */ - Entry() {} - - /** - * Construct a {@link Entry} instance to represent a single record in a - * {@link NetworkStatsHistory} object. - * - * @param bucketStart Start of period for this {@link Entry}, in milliseconds since the - * Unix epoch, see {@link java.lang.System#currentTimeMillis}. - * @param activeTime Active time for this {@link Entry}, in milliseconds. - * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param rxPackets Number of packets received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param operations count of network operations performed for this {@link Entry}. This can - * be used to derive bytes-per-operation. - */ - public Entry(long bucketStart, long activeTime, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { - this.bucketStart = bucketStart; - this.activeTime = activeTime; - this.rxBytes = rxBytes; - this.rxPackets = rxPackets; - this.txBytes = txBytes; - this.txPackets = txPackets; - this.operations = operations; - } - - /** - * Get start timestamp of the bucket's time interval, in milliseconds since the Unix epoch. - */ - public long getBucketStart() { - return bucketStart; - } - - /** - * Get active time of the bucket's time interval, in milliseconds. - */ - public long getActiveTime() { - return activeTime; - } - - /** Get number of bytes received for this {@link Entry}. */ - public long getRxBytes() { - return rxBytes; - } - - /** Get number of packets received for this {@link Entry}. */ - public long getRxPackets() { - return rxPackets; - } - - /** Get number of bytes transmitted for this {@link Entry}. */ - public long getTxBytes() { - return txBytes; - } - - /** Get number of packets transmitted for this {@link Entry}. */ - public long getTxPackets() { - return txPackets; - } - - /** Get count of network operations performed for this {@link Entry}. */ - public long getOperations() { - return operations; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o.getClass() != getClass()) return false; - Entry entry = (Entry) o; - return bucketStart == entry.bucketStart - && activeTime == entry.activeTime && rxBytes == entry.rxBytes - && rxPackets == entry.rxPackets && txBytes == entry.txBytes - && txPackets == entry.txPackets && operations == entry.operations; - } - - @Override - public int hashCode() { - return (int) (bucketStart * 2 - + activeTime * 3 - + rxBytes * 5 - + rxPackets * 7 - + txBytes * 11 - + txPackets * 13 - + operations * 17); - } - - @Override - public String toString() { - return "Entry{" - + "bucketStart=" + bucketStart - + ", activeTime=" + activeTime - + ", rxBytes=" + rxBytes - + ", rxPackets=" + rxPackets - + ", txBytes=" + txBytes - + ", txPackets=" + txPackets - + ", operations=" + operations - + "}"; - } - } - - /** @hide */ - @UnsupportedAppUsage - public NetworkStatsHistory(long bucketDuration) { - this(bucketDuration, 10, FIELD_ALL); - } - - /** @hide */ - public NetworkStatsHistory(long bucketDuration, int initialSize) { - this(bucketDuration, initialSize, FIELD_ALL); - } - - /** @hide */ - public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) { - this.bucketDuration = bucketDuration; - bucketStart = new long[initialSize]; - if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize]; - if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize]; - if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize]; - if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize]; - if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize]; - if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize]; - bucketCount = 0; - totalBytes = 0; - } - - /** @hide */ - public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) { - this(bucketDuration, existing.estimateResizeBuckets(bucketDuration)); - recordEntireHistory(existing); - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public NetworkStatsHistory(Parcel in) { - bucketDuration = in.readLong(); - bucketStart = readLongArray(in); - activeTime = readLongArray(in); - rxBytes = readLongArray(in); - rxPackets = readLongArray(in); - txBytes = readLongArray(in); - txPackets = readLongArray(in); - operations = readLongArray(in); - bucketCount = bucketStart.length; - totalBytes = in.readLong(); - } - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeLong(bucketDuration); - writeLongArray(out, bucketStart, bucketCount); - writeLongArray(out, activeTime, bucketCount); - writeLongArray(out, rxBytes, bucketCount); - writeLongArray(out, rxPackets, bucketCount); - writeLongArray(out, txBytes, bucketCount); - writeLongArray(out, txPackets, bucketCount); - writeLongArray(out, operations, bucketCount); - out.writeLong(totalBytes); - } - - /** @hide */ - public NetworkStatsHistory(DataInput in) throws IOException { - final int version = in.readInt(); - switch (version) { - case VERSION_INIT: { - bucketDuration = in.readLong(); - bucketStart = readFullLongArray(in); - rxBytes = readFullLongArray(in); - rxPackets = new long[bucketStart.length]; - txBytes = readFullLongArray(in); - txPackets = new long[bucketStart.length]; - operations = new long[bucketStart.length]; - bucketCount = bucketStart.length; - totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes); - break; - } - case VERSION_ADD_PACKETS: - case VERSION_ADD_ACTIVE: { - bucketDuration = in.readLong(); - bucketStart = readVarLongArray(in); - activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in) - : new long[bucketStart.length]; - rxBytes = readVarLongArray(in); - rxPackets = readVarLongArray(in); - txBytes = readVarLongArray(in); - txPackets = readVarLongArray(in); - operations = readVarLongArray(in); - bucketCount = bucketStart.length; - totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes); - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - - if (bucketStart.length != bucketCount || rxBytes.length != bucketCount - || rxPackets.length != bucketCount || txBytes.length != bucketCount - || txPackets.length != bucketCount || operations.length != bucketCount) { - throw new ProtocolException("Mismatched history lengths"); - } - } - - /** @hide */ - public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_ACTIVE); - out.writeLong(bucketDuration); - writeVarLongArray(out, bucketStart, bucketCount); - writeVarLongArray(out, activeTime, bucketCount); - writeVarLongArray(out, rxBytes, bucketCount); - writeVarLongArray(out, rxPackets, bucketCount); - writeVarLongArray(out, txBytes, bucketCount); - writeVarLongArray(out, txPackets, bucketCount); - writeVarLongArray(out, operations, bucketCount); - } - - @Override - public int describeContents() { - return 0; - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int size() { - return bucketCount; - } - - /** @hide */ - public long getBucketDuration() { - return bucketDuration; - } - - /** @hide */ - @UnsupportedAppUsage - public long getStart() { - if (bucketCount > 0) { - return bucketStart[0]; - } else { - return Long.MAX_VALUE; - } - } - - /** @hide */ - @UnsupportedAppUsage - public long getEnd() { - if (bucketCount > 0) { - return bucketStart[bucketCount - 1] + bucketDuration; - } else { - return Long.MIN_VALUE; - } - } - - /** - * Return total bytes represented by this history. - * @hide - */ - public long getTotalBytes() { - return totalBytes; - } - - /** - * Return index of bucket that contains or is immediately before the - * requested time. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int getIndexBefore(long time) { - int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); - if (index < 0) { - index = (~index) - 1; - } else { - index -= 1; - } - return NetworkStatsUtils.constrain(index, 0, bucketCount - 1); - } - - /** - * Return index of bucket that contains or is immediately after the - * requested time. - * @hide - */ - public int getIndexAfter(long time) { - int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); - if (index < 0) { - index = ~index; - } else { - index += 1; - } - return NetworkStatsUtils.constrain(index, 0, bucketCount - 1); - } - - /** - * Return specific stats entry. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public Entry getValues(int i, Entry recycle) { - final Entry entry = recycle != null ? recycle : new Entry(); - entry.bucketStart = bucketStart[i]; - entry.bucketDuration = bucketDuration; - entry.activeTime = getLong(activeTime, i, UNKNOWN); - entry.rxBytes = getLong(rxBytes, i, UNKNOWN); - entry.rxPackets = getLong(rxPackets, i, UNKNOWN); - entry.txBytes = getLong(txBytes, i, UNKNOWN); - entry.txPackets = getLong(txPackets, i, UNKNOWN); - entry.operations = getLong(operations, i, UNKNOWN); - return entry; - } - - /** - * Get List of {@link Entry} of the {@link NetworkStatsHistory} instance. - * - * @return - */ - @NonNull - public List<Entry> getEntries() { - // TODO: Return a wrapper that uses this list instead, to prevent the returned result - // from being changed. - final ArrayList<Entry> ret = new ArrayList<>(size()); - for (int i = 0; i < size(); i++) { - ret.add(getValues(i, null /* recycle */)); - } - return ret; - } - - /** @hide */ - public void setValues(int i, Entry entry) { - // Unwind old values - if (rxBytes != null) totalBytes -= rxBytes[i]; - if (txBytes != null) totalBytes -= txBytes[i]; - - bucketStart[i] = entry.bucketStart; - setLong(activeTime, i, entry.activeTime); - setLong(rxBytes, i, entry.rxBytes); - setLong(rxPackets, i, entry.rxPackets); - setLong(txBytes, i, entry.txBytes); - setLong(txPackets, i, entry.txPackets); - setLong(operations, i, entry.operations); - - // Apply new values - if (rxBytes != null) totalBytes += rxBytes[i]; - if (txBytes != null) totalBytes += txBytes[i]; - } - - /** - * Record that data traffic occurred in the given time range. Will - * distribute across internal buckets, creating new buckets as needed. - * @hide - */ - @Deprecated - public void recordData(long start, long end, long rxBytes, long txBytes) { - recordData(start, end, new NetworkStats.Entry( - IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L)); - } - - /** - * Record that data traffic occurred in the given time range. Will - * distribute across internal buckets, creating new buckets as needed. - * @hide - */ - public void recordData(long start, long end, NetworkStats.Entry entry) { - long rxBytes = entry.rxBytes; - long rxPackets = entry.rxPackets; - long txBytes = entry.txBytes; - long txPackets = entry.txPackets; - long operations = entry.operations; - - if (entry.isNegative()) { - throw new IllegalArgumentException("tried recording negative data"); - } - if (entry.isEmpty()) { - return; - } - - // create any buckets needed by this range - ensureBuckets(start, end); - // Return fast if there is still no entry. This would typically happen when the start, - // end or duration are not valid values, e.g. start > end, negative duration value, etc. - if (bucketCount == 0) return; - - // distribute data usage into buckets - long duration = end - start; - final int startIndex = getIndexAfter(end); - for (int i = startIndex; i >= 0; i--) { - final long curStart = bucketStart[i]; - final long curEnd = curStart + bucketDuration; - - // bucket is older than record; we're finished - if (curEnd < start) break; - // bucket is newer than record; keep looking - if (curStart > end) continue; - - final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); - if (overlap <= 0) continue; - - // integer math each time is faster than floating point - final long fracRxBytes = multiplySafeByRational(rxBytes, overlap, duration); - final long fracRxPackets = multiplySafeByRational(rxPackets, overlap, duration); - final long fracTxBytes = multiplySafeByRational(txBytes, overlap, duration); - final long fracTxPackets = multiplySafeByRational(txPackets, overlap, duration); - final long fracOperations = multiplySafeByRational(operations, overlap, duration); - - - addLong(activeTime, i, overlap); - addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes; - addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets; - addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes; - addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets; - addLong(this.operations, i, fracOperations); operations -= fracOperations; - - duration -= overlap; - } - - totalBytes += entry.rxBytes + entry.txBytes; - } - - /** - * Record an entire {@link NetworkStatsHistory} into this history. Usually - * for combining together stats for external reporting. - * @hide - */ - @UnsupportedAppUsage - public void recordEntireHistory(NetworkStatsHistory input) { - recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE); - } - - /** - * Record given {@link NetworkStatsHistory} into this history, copying only - * buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. - * @hide - */ - public void recordHistory(NetworkStatsHistory input, long start, long end) { - final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); - for (int i = 0; i < input.bucketCount; i++) { - final long bucketStart = input.bucketStart[i]; - final long bucketEnd = bucketStart + input.bucketDuration; - - // skip when bucket is outside requested range - if (bucketStart < start || bucketEnd > end) continue; - - entry.rxBytes = getLong(input.rxBytes, i, 0L); - entry.rxPackets = getLong(input.rxPackets, i, 0L); - entry.txBytes = getLong(input.txBytes, i, 0L); - entry.txPackets = getLong(input.txPackets, i, 0L); - entry.operations = getLong(input.operations, i, 0L); - - recordData(bucketStart, bucketEnd, entry); - } - } - - /** - * Ensure that buckets exist for given time range, creating as needed. - */ - private void ensureBuckets(long start, long end) { - // normalize incoming range to bucket boundaries - start -= start % bucketDuration; - end += (bucketDuration - (end % bucketDuration)) % bucketDuration; - - for (long now = start; now < end; now += bucketDuration) { - // try finding existing bucket - final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now); - if (index < 0) { - // bucket missing, create and insert - insertBucket(~index, now); - } - } - } - - /** - * Insert new bucket at requested index and starting time. - */ - private void insertBucket(int index, long start) { - // create more buckets when needed - if (bucketCount >= bucketStart.length) { - final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; - bucketStart = Arrays.copyOf(bucketStart, newLength); - if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength); - if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength); - if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength); - if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength); - if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength); - if (operations != null) operations = Arrays.copyOf(operations, newLength); - } - - // create gap when inserting bucket in middle - if (index < bucketCount) { - final int dstPos = index + 1; - final int length = bucketCount - index; - - System.arraycopy(bucketStart, index, bucketStart, dstPos, length); - if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length); - if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length); - if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length); - if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length); - if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length); - if (operations != null) System.arraycopy(operations, index, operations, dstPos, length); - } - - bucketStart[index] = start; - setLong(activeTime, index, 0L); - setLong(rxBytes, index, 0L); - setLong(rxPackets, index, 0L); - setLong(txBytes, index, 0L); - setLong(txPackets, index, 0L); - setLong(operations, index, 0L); - bucketCount++; - } - - /** - * Clear all data stored in this object. - * @hide - */ - public void clear() { - bucketStart = EmptyArray.LONG; - if (activeTime != null) activeTime = EmptyArray.LONG; - if (rxBytes != null) rxBytes = EmptyArray.LONG; - if (rxPackets != null) rxPackets = EmptyArray.LONG; - if (txBytes != null) txBytes = EmptyArray.LONG; - if (txPackets != null) txPackets = EmptyArray.LONG; - if (operations != null) operations = EmptyArray.LONG; - bucketCount = 0; - totalBytes = 0; - } - - /** - * Remove buckets older than requested cutoff. - * @hide - */ - public void removeBucketsBefore(long cutoff) { - // TODO: Consider use getIndexBefore. - int i; - for (i = 0; i < bucketCount; i++) { - final long curStart = bucketStart[i]; - final long curEnd = curStart + bucketDuration; - - // cutoff happens before or during this bucket; everything before - // this bucket should be removed. - if (curEnd > cutoff) break; - } - - if (i > 0) { - final int length = bucketStart.length; - bucketStart = Arrays.copyOfRange(bucketStart, i, length); - if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length); - if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length); - if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length); - if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length); - if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length); - if (operations != null) operations = Arrays.copyOfRange(operations, i, length); - bucketCount -= i; - - totalBytes = 0; - if (rxBytes != null) totalBytes += CollectionUtils.total(rxBytes); - if (txBytes != null) totalBytes += CollectionUtils.total(txBytes); - } - } - - /** - * Return interpolated data usage across the requested range. Interpolates - * across buckets, so values may be rounded slightly. - * - * <p>If the active bucket is not completed yet, it returns the proportional value of it - * based on its duration and the {@code end} param. - * - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param recycle - entry instance for performance, could be null. - * @hide - */ - @UnsupportedAppUsage - public Entry getValues(long start, long end, Entry recycle) { - return getValues(start, end, Long.MAX_VALUE, recycle); - } - - /** - * Return interpolated data usage across the requested range. Interpolates - * across buckets, so values may be rounded slightly. - * - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param now - current timestamp in milliseconds since the epoch (wall clock). - * @param recycle - entry instance for performance, could be null. - * @hide - */ - @UnsupportedAppUsage - public Entry getValues(long start, long end, long now, Entry recycle) { - final Entry entry = recycle != null ? recycle : new Entry(); - entry.bucketDuration = end - start; - entry.bucketStart = start; - entry.activeTime = activeTime != null ? 0 : UNKNOWN; - entry.rxBytes = rxBytes != null ? 0 : UNKNOWN; - entry.rxPackets = rxPackets != null ? 0 : UNKNOWN; - entry.txBytes = txBytes != null ? 0 : UNKNOWN; - entry.txPackets = txPackets != null ? 0 : UNKNOWN; - entry.operations = operations != null ? 0 : UNKNOWN; - - // Return fast if there is no entry. - if (bucketCount == 0) return entry; - - final int startIndex = getIndexAfter(end); - for (int i = startIndex; i >= 0; i--) { - final long curStart = bucketStart[i]; - long curEnd = curStart + bucketDuration; - - // bucket is older than request; we're finished - if (curEnd <= start) break; - // bucket is newer than request; keep looking - if (curStart >= end) continue; - - // the active bucket is shorter then a normal completed bucket - if (curEnd > now) curEnd = now; - // usually this is simply bucketDuration - final long bucketSpan = curEnd - curStart; - // prevent division by zero - if (bucketSpan <= 0) continue; - - final long overlapEnd = curEnd < end ? curEnd : end; - final long overlapStart = curStart > start ? curStart : start; - final long overlap = overlapEnd - overlapStart; - if (overlap <= 0) continue; - - // integer math each time is faster than floating point - if (activeTime != null) { - entry.activeTime += multiplySafeByRational(activeTime[i], overlap, bucketSpan); - } - if (rxBytes != null) { - entry.rxBytes += multiplySafeByRational(rxBytes[i], overlap, bucketSpan); - } - if (rxPackets != null) { - entry.rxPackets += multiplySafeByRational(rxPackets[i], overlap, bucketSpan); - } - if (txBytes != null) { - entry.txBytes += multiplySafeByRational(txBytes[i], overlap, bucketSpan); - } - if (txPackets != null) { - entry.txPackets += multiplySafeByRational(txPackets[i], overlap, bucketSpan); - } - if (operations != null) { - entry.operations += multiplySafeByRational(operations[i], overlap, bucketSpan); - } - } - return entry; - } - - /** - * @deprecated only for temporary testing - * @hide - */ - @Deprecated - public void generateRandom(long start, long end, long bytes) { - final Random r = new Random(); - - final float fractionRx = r.nextFloat(); - final long rxBytes = (long) (bytes * fractionRx); - final long txBytes = (long) (bytes * (1 - fractionRx)); - - final long rxPackets = rxBytes / 1024; - final long txPackets = txBytes / 1024; - final long operations = rxBytes / 2048; - - generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r); - } - - /** - * @deprecated only for temporary testing - * @hide - */ - @Deprecated - public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes, - long txPackets, long operations, Random r) { - ensureBuckets(start, end); - - final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); - while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128 - || operations > 32) { - final long curStart = randomLong(r, start, end); - final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2); - - entry.rxBytes = randomLong(r, 0, rxBytes); - entry.rxPackets = randomLong(r, 0, rxPackets); - entry.txBytes = randomLong(r, 0, txBytes); - entry.txPackets = randomLong(r, 0, txPackets); - entry.operations = randomLong(r, 0, operations); - - rxBytes -= entry.rxBytes; - rxPackets -= entry.rxPackets; - txBytes -= entry.txBytes; - txPackets -= entry.txPackets; - operations -= entry.operations; - - recordData(curStart, curEnd, entry); - } - } - - /** @hide */ - public static long randomLong(Random r, long start, long end) { - return (long) (start + (r.nextFloat() * (end - start))); - } - - /** - * Quickly determine if this history intersects with given window. - * @hide - */ - public boolean intersects(long start, long end) { - final long dataStart = getStart(); - final long dataEnd = getEnd(); - if (start >= dataStart && start <= dataEnd) return true; - if (end >= dataStart && end <= dataEnd) return true; - if (dataStart >= start && dataStart <= end) return true; - if (dataEnd >= start && dataEnd <= end) return true; - return false; - } - - /** @hide */ - public void dump(IndentingPrintWriter pw, boolean fullHistory) { - pw.print("NetworkStatsHistory: bucketDuration="); - pw.println(bucketDuration / SECOND_IN_MILLIS); - pw.increaseIndent(); - - final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); - if (start > 0) { - pw.print("(omitting "); pw.print(start); pw.println(" buckets)"); - } - - for (int i = start; i < bucketCount; i++) { - pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS); - if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); } - if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); } - if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); } - if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); } - if (operations != null) { pw.print(" op="); pw.print(operations[i]); } - pw.println(); - } - - pw.decreaseIndent(); - } - - /** @hide */ - public void dumpCheckin(PrintWriter pw) { - pw.print("d,"); - pw.print(bucketDuration / SECOND_IN_MILLIS); - pw.println(); - - for (int i = 0; i < bucketCount; i++) { - pw.print("b,"); - pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(','); - if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(','); - if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(','); - if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(','); - if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(','); - if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); } - pw.println(); - } - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); - - for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); - - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, - bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); - - proto.end(startBucket); - } - - proto.end(start); - } - - private static void dumpDebug(ProtoOutputStream proto, long tag, long[] array, int index) { - if (array != null) { - proto.write(tag, array[index]); - } - } - - @Override - public String toString() { - final CharArrayWriter writer = new CharArrayWriter(); - dump(new IndentingPrintWriter(writer, " "), false); - return writer.toString(); - } - - @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() { - @Override - public NetworkStatsHistory createFromParcel(Parcel in) { - return new NetworkStatsHistory(in); - } - - @Override - public NetworkStatsHistory[] newArray(int size) { - return new NetworkStatsHistory[size]; - } - }; - - private static long getLong(long[] array, int i, long value) { - return array != null ? array[i] : value; - } - - private static void setLong(long[] array, int i, long value) { - if (array != null) array[i] = value; - } - - private static void addLong(long[] array, int i, long value) { - if (array != null) array[i] += value; - } - - /** @hide */ - public int estimateResizeBuckets(long newBucketDuration) { - return (int) (size() * getBucketDuration() / newBucketDuration); - } - - /** - * Utility methods for interacting with {@link DataInputStream} and - * {@link DataOutputStream}, mostly dealing with writing partial arrays. - * @hide - */ - public static class DataStreamUtils { - @Deprecated - public static long[] readFullLongArray(DataInput in) throws IOException { - final int size = in.readInt(); - if (size < 0) throw new ProtocolException("negative array size"); - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readLong(); - } - return values; - } - - /** - * Read variable-length {@link Long} using protobuf-style approach. - */ - public static long readVarLong(DataInput in) throws IOException { - int shift = 0; - long result = 0; - while (shift < 64) { - byte b = in.readByte(); - result |= (long) (b & 0x7F) << shift; - if ((b & 0x80) == 0) - return result; - shift += 7; - } - throw new ProtocolException("malformed long"); - } - - /** - * Write variable-length {@link Long} using protobuf-style approach. - */ - public static void writeVarLong(DataOutput out, long value) throws IOException { - while (true) { - if ((value & ~0x7FL) == 0) { - out.writeByte((int) value); - return; - } else { - out.writeByte(((int) value & 0x7F) | 0x80); - value >>>= 7; - } - } - } - - public static long[] readVarLongArray(DataInput in) throws IOException { - final int size = in.readInt(); - if (size == -1) return null; - if (size < 0) throw new ProtocolException("negative array size"); - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = readVarLong(in); - } - return values; - } - - public static void writeVarLongArray(DataOutput out, long[] values, int size) - throws IOException { - if (values == null) { - out.writeInt(-1); - return; - } - if (size > values.length) { - throw new IllegalArgumentException("size larger than length"); - } - out.writeInt(size); - for (int i = 0; i < size; i++) { - writeVarLong(out, values[i]); - } - } - } - - /** - * Utility methods for interacting with {@link Parcel} structures, mostly - * dealing with writing partial arrays. - * @hide - */ - public static class ParcelUtils { - public static long[] readLongArray(Parcel in) { - final int size = in.readInt(); - if (size == -1) return null; - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readLong(); - } - return values; - } - - public static void writeLongArray(Parcel out, long[] values, int size) { - if (values == null) { - out.writeInt(-1); - return; - } - if (size > values.length) { - throw new IllegalArgumentException("size larger than length"); - } - out.writeInt(size); - for (int i = 0; i < size; i++) { - out.writeLong(values[i]); - } - } - } - - /** - * Builder class for {@link NetworkStatsHistory}. - */ - public static final class Builder { - private final long mBucketDuration; - private final List<Long> mBucketStart; - private final List<Long> mActiveTime; - private final List<Long> mRxBytes; - private final List<Long> mRxPackets; - private final List<Long> mTxBytes; - private final List<Long> mTxPackets; - private final List<Long> mOperations; - - /** - * Creates a new Builder with given bucket duration and initial capacity to construct - * {@link NetworkStatsHistory} objects. - * - * @param bucketDuration Duration of the buckets of the object, in milliseconds. - * @param initialCapacity Estimated number of records. - */ - public Builder(long bucketDuration, int initialCapacity) { - mBucketDuration = bucketDuration; - mBucketStart = new ArrayList<>(initialCapacity); - mActiveTime = new ArrayList<>(initialCapacity); - mRxBytes = new ArrayList<>(initialCapacity); - mRxPackets = new ArrayList<>(initialCapacity); - mTxBytes = new ArrayList<>(initialCapacity); - mTxPackets = new ArrayList<>(initialCapacity); - mOperations = new ArrayList<>(initialCapacity); - } - - /** - * Add an {@link Entry} into the {@link NetworkStatsHistory} instance. - * - * @param entry The target {@link Entry} object. - * @return The builder object. - */ - @NonNull - public Builder addEntry(@NonNull Entry entry) { - mBucketStart.add(entry.bucketStart); - mActiveTime.add(entry.activeTime); - mRxBytes.add(entry.rxBytes); - mRxPackets.add(entry.rxPackets); - mTxBytes.add(entry.txBytes); - mTxPackets.add(entry.txPackets); - mOperations.add(entry.operations); - return this; - } - - private static long sum(@NonNull List<Long> list) { - long sum = 0; - for (long entry : list) { - sum += entry; - } - return sum; - } - - /** - * Builds the instance of the {@link NetworkStatsHistory}. - * - * @return the built instance of {@link NetworkStatsHistory}. - */ - @NonNull - public NetworkStatsHistory build() { - return new NetworkStatsHistory(mBucketDuration, - CollectionUtils.toLongArray(mBucketStart), - CollectionUtils.toLongArray(mActiveTime), - CollectionUtils.toLongArray(mRxBytes), - CollectionUtils.toLongArray(mRxPackets), - CollectionUtils.toLongArray(mTxBytes), - CollectionUtils.toLongArray(mTxPackets), - CollectionUtils.toLongArray(mOperations), - mBucketStart.size(), - sum(mRxBytes) + sum(mTxBytes)); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java deleted file mode 100644 index 7b5afd720016..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java +++ /dev/null @@ -1,1119 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.ConnectivityManager.TYPE_BLUETOOTH; -import static android.net.ConnectivityManager.TYPE_ETHERNET; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_PROXY; -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.TYPE_WIFI_P2P; -import static android.net.ConnectivityManager.TYPE_WIMAX; -import static android.net.NetworkIdentity.OEM_NONE; -import static android.net.NetworkIdentity.OEM_PAID; -import static android.net.NetworkIdentity.OEM_PRIVATE; -import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; -import static android.net.NetworkStats.DEFAULT_NETWORK_NO; -import static android.net.NetworkStats.DEFAULT_NETWORK_YES; -import static android.net.NetworkStats.METERED_ALL; -import static android.net.NetworkStats.METERED_NO; -import static android.net.NetworkStats.METERED_YES; -import static android.net.NetworkStats.ROAMING_ALL; -import static android.net.NetworkStats.ROAMING_NO; -import static android.net.NetworkStats.ROAMING_YES; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.app.usage.NetworkStatsManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.wifi.WifiInfo; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.ArraySet; - -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkIdentityUtils; -import com.android.net.module.util.NetworkStatsUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -/** - * Predicate used to match {@link NetworkIdentity}, usually when collecting - * statistics. (It should probably have been named {@code NetworkPredicate}.) - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class NetworkTemplate implements Parcelable { - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "MATCH_" }, value = { - MATCH_MOBILE, - MATCH_WIFI, - MATCH_ETHERNET, - MATCH_BLUETOOTH, - MATCH_PROXY, - MATCH_CARRIER, - }) - public @interface TemplateMatchRule{} - - /** Match rule to match cellular networks with given Subscriber Ids. */ - public static final int MATCH_MOBILE = 1; - /** Match rule to match wifi networks. */ - public static final int MATCH_WIFI = 4; - /** Match rule to match ethernet networks. */ - public static final int MATCH_ETHERNET = 5; - /** - * Match rule to match all cellular networks. - * - * @hide - */ - public static final int MATCH_MOBILE_WILDCARD = 6; - /** - * Match rule to match all wifi networks. - * - * @hide - */ - public static final int MATCH_WIFI_WILDCARD = 7; - /** Match rule to match bluetooth networks. */ - public static final int MATCH_BLUETOOTH = 8; - /** - * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy - * network type. - */ - public static final int MATCH_PROXY = 9; - /** - * Match rule to match all networks with subscriberId inside the template. Some carriers - * may offer non-cellular networks like WiFi, which will be matched by this rule. - */ - public static final int MATCH_CARRIER = 10; - - // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL. - /** @hide */ - public static final String WIFI_NETWORKID_ALL = null; - - /** - * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that - * should be fixed), so it's not possible to want to match null vs - * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key. - * - * @hide - */ - public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL; - - /** - * Include all network types when filtering. This is meant to merge in with the - * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. - */ - public static final int NETWORK_TYPE_ALL = -1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "OEM_MANAGED_" }, value = { - OEM_MANAGED_ALL, - OEM_MANAGED_NO, - OEM_MANAGED_YES, - OEM_MANAGED_PAID, - OEM_MANAGED_PRIVATE - }) - public @interface OemManaged{} - - /** - * Value to match both OEM managed and unmanaged networks (all networks). - */ - public static final int OEM_MANAGED_ALL = -1; - /** - * Value to match networks which are not OEM managed. - */ - public static final int OEM_MANAGED_NO = OEM_NONE; - /** - * Value to match any OEM managed network. - */ - public static final int OEM_MANAGED_YES = -2; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. - */ - public static final int OEM_MANAGED_PAID = OEM_PAID; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. - */ - public static final int OEM_MANAGED_PRIVATE = OEM_PRIVATE; - - private static boolean isKnownMatchRule(final int rule) { - switch (rule) { - case MATCH_MOBILE: - case MATCH_WIFI: - case MATCH_ETHERNET: - case MATCH_MOBILE_WILDCARD: - case MATCH_WIFI_WILDCARD: - case MATCH_BLUETOOTH: - case MATCH_PROXY: - case MATCH_CARRIER: - return true; - - default: - return false; - } - } - - /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with - * the given IMSI. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE, subscriberId, null); - } - - /** - * Template to match cellular networks with the given IMSI, {@code ratType} and - * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when - * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. - * - * @hide - */ - public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - int ratType, int metered) { - if (TextUtils.isEmpty(subscriberId)) { - return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */, - null /* matchSubscriberIds */, - new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL, - DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId }, - new String[0] /* matchWifiNetworkKeys */, - metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** - * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, - * regardless of IMSI. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static NetworkTemplate buildTemplateMobileWildcard() { - return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); - } - - /** - * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, - * regardless of key of the wifi network. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateWifiWildcard() { - // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL - // and SUBSCRIBER_ID_MATCH_RULE_ALL. - return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); - } - - /** @hide */ - @Deprecated - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateWifi() { - return buildTemplateWifiWildcard(); - } - - /** - * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the - * given key of the wifi network. - * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} - * to know details about the key. - * @hide - */ - public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) { - Objects.requireNonNull(wifiNetworkKey); - return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, - new String[] { null } /* matchSubscriberIds */, - new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL); - } - - /** - * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given - * key of the wifi network and IMSI. - * - * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless - * of key of the wifi network. - * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} - * to know details about the key. - * @param subscriberId the IMSI associated to this wifi network. - * - * @hide - */ - public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey, - @Nullable String subscriberId) { - return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, - wifiNetworkKey != null - ? new String[] { wifiNetworkKey } : new String[0], - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** - * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style - * networks together. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateEthernet() { - return new NetworkTemplate(MATCH_ETHERNET, null, null); - } - - /** - * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style - * networks together. - * - * @hide - */ - public static NetworkTemplate buildTemplateBluetooth() { - return new NetworkTemplate(MATCH_BLUETOOTH, null, null); - } - - /** - * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style - * networks together. - * - * @hide - */ - public static NetworkTemplate buildTemplateProxy() { - return new NetworkTemplate(MATCH_PROXY, null, null); - } - - /** - * Template to match all metered carrier networks with the given IMSI. - * - * @hide - */ - public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { - Objects.requireNonNull(subscriberId); - return new NetworkTemplate(MATCH_CARRIER, subscriberId, - new String[] { subscriberId }, - new String[0] /* matchWifiNetworkKeys */, - METERED_YES, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - private final int mMatchRule; - private final String mSubscriberId; - - /** - * Ugh, templates are designed to target a single subscriber, but we might - * need to match several "merged" subscribers. These are the subscribers - * that should be considered to match this template. - * <p> - * Since the merge set is dynamic, it should <em>not</em> be persisted or - * used for determining equality. - */ - private final String[] mMatchSubscriberIds; - - @NonNull - private final String[] mMatchWifiNetworkKeys; - - // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. - private final int mMetered; - private final int mRoaming; - private final int mDefaultNetwork; - private final int mRatType; - /** - * The subscriber Id match rule defines how the template should match networks with - * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail. - */ - private final int mSubscriberIdMatchRule; - - // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. - private final int mOemManaged; - - private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) { - switch (matchRule) { - case MATCH_MOBILE: - case MATCH_CARRIER: - // MOBILE and CARRIER templates must always specify a subscriber ID. - if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) { - throw new IllegalArgumentException("Invalid SubscriberIdMatchRule " - + "on match rule: " + getMatchRuleName(matchRule)); - } - return; - default: - return; - } - } - - /** @hide */ - // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) - @UnsupportedAppUsage - public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) { - this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey); - } - - /** @hide */ - public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String wifiNetworkKey) { - // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates - // to metered networks. It is now possible to match mobile with any meteredness, but - // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this - //constructor passes METERED_YES for these types. - this(matchRule, subscriberId, matchSubscriberIds, - wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], - (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES - : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** @hide */ - // TODO: Remove it after updating all of the caller. - public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int ratType, - int oemManaged) { - this(matchRule, subscriberId, matchSubscriberIds, - wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], - metered, roaming, defaultNetwork, ratType, oemManaged, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** @hide */ - public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String[] matchWifiNetworkKeys, int metered, int roaming, - int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule) { - Objects.requireNonNull(matchWifiNetworkKeys); - mMatchRule = matchRule; - mSubscriberId = subscriberId; - // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when - // mSubscriberId is null - mMatchSubscriberIds = matchSubscriberIds; - mMatchWifiNetworkKeys = matchWifiNetworkKeys; - mMetered = metered; - mRoaming = roaming; - mDefaultNetwork = defaultNetwork; - mRatType = ratType; - mOemManaged = oemManaged; - mSubscriberIdMatchRule = subscriberIdMatchRule; - checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule); - if (!isKnownMatchRule(matchRule)) { - throw new IllegalArgumentException("Unknown network template rule " + matchRule - + " will not match any identity."); - } - } - - private NetworkTemplate(Parcel in) { - mMatchRule = in.readInt(); - mSubscriberId = in.readString(); - mMatchSubscriberIds = in.createStringArray(); - mMatchWifiNetworkKeys = in.createStringArray(); - mMetered = in.readInt(); - mRoaming = in.readInt(); - mDefaultNetwork = in.readInt(); - mRatType = in.readInt(); - mOemManaged = in.readInt(); - mSubscriberIdMatchRule = in.readInt(); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mMatchRule); - dest.writeString(mSubscriberId); - dest.writeStringArray(mMatchSubscriberIds); - dest.writeStringArray(mMatchWifiNetworkKeys); - dest.writeInt(mMetered); - dest.writeInt(mRoaming); - dest.writeInt(mDefaultNetwork); - dest.writeInt(mRatType); - dest.writeInt(mOemManaged); - dest.writeInt(mSubscriberIdMatchRule); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder("NetworkTemplate: "); - builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); - if (mSubscriberId != null) { - builder.append(", subscriberId=").append( - NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); - } - if (mMatchSubscriberIds != null) { - builder.append(", matchSubscriberIds=").append( - Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds))); - } - builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys)); - if (mMetered != METERED_ALL) { - builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); - } - if (mRoaming != ROAMING_ALL) { - builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming)); - } - if (mDefaultNetwork != DEFAULT_NETWORK_ALL) { - builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( - mDefaultNetwork)); - } - if (mRatType != NETWORK_TYPE_ALL) { - builder.append(", ratType=").append(mRatType); - } - if (mOemManaged != OEM_MANAGED_ALL) { - builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); - } - builder.append(", subscriberIdMatchRule=") - .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); - return builder.toString(); - } - - @Override - public int hashCode() { - return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys), - mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, mSubscriberIdMatchRule); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof NetworkTemplate) { - final NetworkTemplate other = (NetworkTemplate) obj; - return mMatchRule == other.mMatchRule - && Objects.equals(mSubscriberId, other.mSubscriberId) - && mMetered == other.mMetered - && mRoaming == other.mRoaming - && mDefaultNetwork == other.mDefaultNetwork - && mRatType == other.mRatType - && mOemManaged == other.mOemManaged - && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule - && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys); - } - return false; - } - - private static String subscriberIdMatchRuleToString(int rule) { - switch (rule) { - case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT: - return "EXACT_MATCH"; - case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL: - return "ALL"; - default: - return "Unknown rule " + rule; - } - } - - /** @hide */ - public boolean isMatchRuleMobile() { - switch (mMatchRule) { - case MATCH_MOBILE: - case MATCH_MOBILE_WILDCARD: - return true; - default: - return false; - } - } - - /** - * Get match rule of the template. See {@code MATCH_*}. - */ - @UnsupportedAppUsage - public int getMatchRule() { - // Wildcard rules are not exposed. For external callers, convert wildcard rules to - // exposed rules before returning. - switch (mMatchRule) { - case MATCH_MOBILE_WILDCARD: - return MATCH_MOBILE; - case MATCH_WIFI_WILDCARD: - return MATCH_WIFI; - default: - return mMatchRule; - } - } - - /** - * Get subscriber Id of the template. - * @hide - */ - @Nullable - @UnsupportedAppUsage - public String getSubscriberId() { - return mSubscriberId; - } - - /** - * Get set of subscriber Ids of the template. - */ - @NonNull - public Set<String> getSubscriberIds() { - return new ArraySet<>(Arrays.asList(mMatchSubscriberIds)); - } - - /** - * Get the set of Wifi Network Keys of the template. - * See {@link WifiInfo#getNetworkKey()}. - */ - @NonNull - public Set<String> getWifiNetworkKeys() { - return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys)); - } - - /** @hide */ - // TODO: Remove this and replace all callers with {@link #getWifiNetworkKeys()}. - @Nullable - public String getNetworkId() { - return getWifiNetworkKeys().isEmpty() ? null : getWifiNetworkKeys().iterator().next(); - } - - /** - * Get meteredness filter of the template. - */ - @NetworkStats.Meteredness - public int getMeteredness() { - return mMetered; - } - - /** - * Get roaming filter of the template. - */ - @NetworkStats.Roaming - public int getRoaming() { - return mRoaming; - } - - /** - * Get the default network status filter of the template. - */ - @NetworkStats.DefaultNetwork - public int getDefaultNetworkStatus() { - return mDefaultNetwork; - } - - /** - * Get the Radio Access Technology(RAT) type filter of the template. - */ - public int getRatType() { - return mRatType; - } - - /** - * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or - * {@code android.net.NetworkIdentity#OEM_*}. - */ - @OemManaged - public int getOemManaged() { - return mOemManaged; - } - - /** - * Test if given {@link NetworkIdentity} matches this template. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public boolean matches(@NonNull NetworkIdentity ident) { - Objects.requireNonNull(ident); - if (!matchesMetered(ident)) return false; - if (!matchesRoaming(ident)) return false; - if (!matchesDefaultNetwork(ident)) return false; - if (!matchesOemNetwork(ident)) return false; - - switch (mMatchRule) { - case MATCH_MOBILE: - return matchesMobile(ident); - case MATCH_WIFI: - return matchesWifi(ident); - case MATCH_ETHERNET: - return matchesEthernet(ident); - case MATCH_MOBILE_WILDCARD: - return matchesMobileWildcard(ident); - case MATCH_WIFI_WILDCARD: - return matchesWifiWildcard(ident); - case MATCH_BLUETOOTH: - return matchesBluetooth(ident); - case MATCH_PROXY: - return matchesProxy(ident); - case MATCH_CARRIER: - return matchesCarrier(ident); - default: - // We have no idea what kind of network template we are, so we - // just claim not to match anything. - return false; - } - } - - private boolean matchesMetered(NetworkIdentity ident) { - return (mMetered == METERED_ALL) - || (mMetered == METERED_YES && ident.mMetered) - || (mMetered == METERED_NO && !ident.mMetered); - } - - private boolean matchesRoaming(NetworkIdentity ident) { - return (mRoaming == ROAMING_ALL) - || (mRoaming == ROAMING_YES && ident.mRoaming) - || (mRoaming == ROAMING_NO && !ident.mRoaming); - } - - private boolean matchesDefaultNetwork(NetworkIdentity ident) { - return (mDefaultNetwork == DEFAULT_NETWORK_ALL) - || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork) - || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); - } - - private boolean matchesOemNetwork(NetworkIdentity ident) { - return (mOemManaged == OEM_MANAGED_ALL) - || (mOemManaged == OEM_MANAGED_YES - && ident.mOemManaged != OEM_NONE) - || (mOemManaged == ident.mOemManaged); - } - - private boolean matchesCollapsedRatType(NetworkIdentity ident) { - return mRatType == NETWORK_TYPE_ALL - || NetworkStatsManager.getCollapsedRatType(mRatType) - == NetworkStatsManager.getCollapsedRatType(ident.mRatType); - } - - /** - * Check if this template matches {@code subscriberId}. Returns true if this - * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a - * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. - * - * @hide - */ - public boolean matchesSubscriberId(@Nullable String subscriberId) { - return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL - || CollectionUtils.contains(mMatchSubscriberIds, subscriberId); - } - - /** - * Check if network matches key of the wifi network. - * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is - * empty. - * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} - * to know details about the key. - */ - private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) { - Objects.requireNonNull(wifiNetworkKey); - return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) - || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey); - } - - /** - * Check if mobile network matches IMSI. - */ - private boolean matchesMobile(NetworkIdentity ident) { - if (ident.mType == TYPE_WIMAX) { - // TODO: consider matching against WiMAX subscriber identity - return true; - } else { - return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds) - && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) - && matchesCollapsedRatType(ident); - } - } - - /** - * Check if matches Wi-Fi network template. - */ - private boolean matchesWifi(NetworkIdentity ident) { - switch (ident.mType) { - case TYPE_WIFI: - return matchesSubscriberId(ident.mSubscriberId) - && matchesWifiNetworkKey(ident.mWifiNetworkKey); - default: - return false; - } - } - - /** - * Check if matches Ethernet network template. - */ - private boolean matchesEthernet(NetworkIdentity ident) { - if (ident.mType == TYPE_ETHERNET) { - return true; - } - return false; - } - - /** - * Check if matches carrier network. The carrier networks means it includes the subscriberId. - */ - private boolean matchesCarrier(NetworkIdentity ident) { - return ident.mSubscriberId != null - && !CollectionUtils.isEmpty(mMatchSubscriberIds) - && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); - } - - private boolean matchesMobileWildcard(NetworkIdentity ident) { - if (ident.mType == TYPE_WIMAX) { - return true; - } else { - return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); - } - } - - private boolean matchesWifiWildcard(NetworkIdentity ident) { - switch (ident.mType) { - case TYPE_WIFI: - case TYPE_WIFI_P2P: - return true; - default: - return false; - } - } - - /** - * Check if matches Bluetooth network template. - */ - private boolean matchesBluetooth(NetworkIdentity ident) { - if (ident.mType == TYPE_BLUETOOTH) { - return true; - } - return false; - } - - /** - * Check if matches Proxy network template. - */ - private boolean matchesProxy(NetworkIdentity ident) { - return ident.mType == TYPE_PROXY; - } - - private static String getMatchRuleName(int matchRule) { - switch (matchRule) { - case MATCH_MOBILE: - return "MOBILE"; - case MATCH_WIFI: - return "WIFI"; - case MATCH_ETHERNET: - return "ETHERNET"; - case MATCH_MOBILE_WILDCARD: - return "MOBILE_WILDCARD"; - case MATCH_WIFI_WILDCARD: - return "WIFI_WILDCARD"; - case MATCH_BLUETOOTH: - return "BLUETOOTH"; - case MATCH_PROXY: - return "PROXY"; - case MATCH_CARRIER: - return "CARRIER"; - default: - return "UNKNOWN(" + matchRule + ")"; - } - } - - private static String getOemManagedNames(int oemManaged) { - switch (oemManaged) { - case OEM_MANAGED_ALL: - return "OEM_MANAGED_ALL"; - case OEM_MANAGED_NO: - return "OEM_MANAGED_NO"; - case OEM_MANAGED_YES: - return "OEM_MANAGED_YES"; - default: - return NetworkIdentity.getOemManagedNames(oemManaged); - } - } - - /** - * Examine the given template and normalize it. - * We pick the "lowest" merged subscriber as the primary - * for key purposes, and expand the template to match all other merged - * subscribers. - * <p> - * For example, given an incoming template matching B, and the currently - * active merge set [A,B], we'd return a new template that primarily matches - * A, but also matches B. - * TODO: remove and use {@link #normalize(NetworkTemplate, List)}. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { - return normalize(template, Arrays.<String[]>asList(merged)); - } - - /** - * Examine the given template and normalize it. - * We pick the "lowest" merged subscriber as the primary - * for key purposes, and expand the template to match all other merged - * subscribers. - * - * There can be multiple merged subscriberIds for multi-SIM devices. - * - * <p> - * For example, given an incoming template matching B, and the currently - * active merge set [A,B], we'd return a new template that primarily matches - * A, but also matches B. - * - * @hide - */ - // TODO: @SystemApi when ready. - public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { - // Now there are several types of network which uses SubscriberId to store network - // information. For instances: - // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. - // The TYPE_CARRIER means that the network associate to specific carrier network. - - if (template.mSubscriberId == null) return template; - - for (String[] merged : mergedList) { - if (CollectionUtils.contains(merged, template.mSubscriberId)) { - // Requested template subscriber is part of the merge group; return - // a template that matches all merged subscribers. - final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys; - return new NetworkTemplate(template.mMatchRule, merged[0], merged, - CollectionUtils.isEmpty(matchWifiNetworkKeys) - ? null : matchWifiNetworkKeys[0]); - } - } - - return template; - } - - @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() { - @Override - public NetworkTemplate createFromParcel(Parcel in) { - return new NetworkTemplate(in); - } - - @Override - public NetworkTemplate[] newArray(int size) { - return new NetworkTemplate[size]; - } - }; - - /** - * Builder class for NetworkTemplate. - */ - public static final class Builder { - private final int mMatchRule; - // Use a SortedSet to provide a deterministic order when fetching the first one. - @NonNull - private final SortedSet<String> mMatchSubscriberIds = - new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder())); - @NonNull - private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>(); - - // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. - private int mMetered; - private int mRoaming; - private int mDefaultNetwork; - private int mRatType; - - // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}. - private int mOemManaged; - - /** - * Creates a new Builder with given match rule to construct NetworkTemplate objects. - * - * @param matchRule the match rule of the template, see {@code MATCH_*}. - */ - public Builder(@TemplateMatchRule final int matchRule) { - assertRequestableMatchRule(matchRule); - // Initialize members with default values. - mMatchRule = matchRule; - mMetered = METERED_ALL; - mRoaming = ROAMING_ALL; - mDefaultNetwork = DEFAULT_NETWORK_ALL; - mRatType = NETWORK_TYPE_ALL; - mOemManaged = OEM_MANAGED_ALL; - } - - /** - * Set the Subscriber Ids. Calling this function with an empty set represents - * the intention of matching any Subscriber Ids. - * - * @param subscriberIds the list of Subscriber Ids. - * @return this builder. - */ - @NonNull - public Builder setSubscriberIds(@NonNull Set<String> subscriberIds) { - Objects.requireNonNull(subscriberIds); - mMatchSubscriberIds.clear(); - mMatchSubscriberIds.addAll(subscriberIds); - return this; - } - - /** - * Set the Wifi Network Keys. Calling this function with an empty set represents - * the intention of matching any Wifi Network Key. - * - * @param wifiNetworkKeys the list of Wifi Network Key, - * see {@link WifiInfo#getNetworkKey()}. - * Or an empty list to match all networks. - * Note that {@code getNetworkKey()} might get null key - * when wifi disconnects. However, the caller should never invoke - * this function with a null Wifi Network Key since such statistics - * never exists. - * @return this builder. - */ - @NonNull - public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) { - Objects.requireNonNull(wifiNetworkKeys); - for (String key : wifiNetworkKeys) { - if (key == null) { - throw new IllegalArgumentException("Null is not a valid key"); - } - } - mMatchWifiNetworkKeys.clear(); - mMatchWifiNetworkKeys.addAll(wifiNetworkKeys); - return this; - } - - /** - * Set the meteredness filter. - * - * @param metered the meteredness filter. - * @return this builder. - */ - @NonNull - public Builder setMeteredness(@NetworkStats.Meteredness int metered) { - mMetered = metered; - return this; - } - - /** - * Set the roaming filter. - * - * @param roaming the roaming filter. - * @return this builder. - */ - @NonNull - public Builder setRoaming(@NetworkStats.Roaming int roaming) { - mRoaming = roaming; - return this; - } - - /** - * Set the default network status filter. - * - * @param defaultNetwork the default network status filter. - * @return this builder. - */ - @NonNull - public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) { - mDefaultNetwork = defaultNetwork; - return this; - } - - /** - * Set the Radio Access Technology(RAT) type filter. - * - * @param ratType the Radio Access Technology(RAT) type filter. Use - * {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. - * @return this builder. - */ - @NonNull - public Builder setRatType(int ratType) { - // Input will be validated with the match rule when building the template. - mRatType = ratType; - return this; - } - - /** - * Set the OEM managed filter. - * - * @param oemManaged the match rule to match different type of OEM managed network or - * unmanaged networks. See {@code OEM_MANAGED_*}. - * @return this builder. - */ - @NonNull - public Builder setOemManaged(@OemManaged int oemManaged) { - mOemManaged = oemManaged; - return this; - } - - /** - * Check whether the match rule is requestable. - * - * @param matchRule the target match rule to be checked. - */ - private static void assertRequestableMatchRule(final int matchRule) { - if (!isKnownMatchRule(matchRule) - || matchRule == MATCH_PROXY - || matchRule == MATCH_MOBILE_WILDCARD - || matchRule == MATCH_WIFI_WILDCARD) { - throw new IllegalArgumentException("Invalid match rule: " - + getMatchRuleName(matchRule)); - } - } - - private void assertRequestableParameters() { - validateWifiNetworkKeys(); - // TODO: Check all the input are legitimate. - } - - private void validateWifiNetworkKeys() { - if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) { - throw new IllegalArgumentException("Trying to build non wifi match rule: " - + mMatchRule + " with wifi network keys"); - } - } - - /** - * For backward compatibility, deduce match rule to a wildcard match rule - * if the Subscriber Ids are empty. - */ - private int getWildcardDeducedMatchRule() { - if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) { - return MATCH_MOBILE_WILDCARD; - } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty() - && mMatchWifiNetworkKeys.isEmpty()) { - return MATCH_WIFI_WILDCARD; - } - return mMatchRule; - } - - /** - * Builds the instance of the NetworkTemplate. - * - * @return the built instance of NetworkTemplate. - */ - @NonNull - public NetworkTemplate build() { - assertRequestableParameters(); - final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty() - ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL - : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT; - return new NetworkTemplate(getWildcardDeducedMatchRule(), - mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(), - mMatchSubscriberIds.toArray(new String[0]), - mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming, - mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java deleted file mode 100644 index dc4ac552a4bb..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java +++ /dev/null @@ -1,1148 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.NonNull; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.annotation.TestApi; -import android.app.DownloadManager; -import android.app.backup.BackupManager; -import android.app.usage.NetworkStatsManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.media.MediaPlayer; -import android.os.Binder; -import android.os.Build; -import android.os.RemoteException; -import android.os.StrictMode; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.DatagramSocket; -import java.net.Socket; -import java.net.SocketException; - -/** - * Class that provides network traffic statistics. These statistics include - * bytes transmitted and received and network packets transmitted and received, - * over all interfaces, over the mobile interface, and on a per-UID basis. - * <p> - * These statistics may not be available on all platforms. If the statistics are - * not supported by this device, {@link #UNSUPPORTED} will be returned. - * <p> - * Note that the statistics returned by this class reset and start from zero - * after every reboot. To access more robust historical network statistics data, - * use {@link NetworkStatsManager} instead. - */ -public class TrafficStats { - static { - System.loadLibrary("framework-connectivity-tiramisu-jni"); - } - - private static final String TAG = TrafficStats.class.getSimpleName(); - /** - * The return value to indicate that the device does not support the statistic. - */ - public final static int UNSUPPORTED = -1; - - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long KB_IN_BYTES = 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long MB_IN_BYTES = KB_IN_BYTES * 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long TB_IN_BYTES = GB_IN_BYTES * 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long PB_IN_BYTES = TB_IN_BYTES * 1024; - - /** - * Special UID value used when collecting {@link NetworkStatsHistory} for - * removed applications. - * - * @hide - */ - public static final int UID_REMOVED = -4; - - /** - * Special UID value used when collecting {@link NetworkStatsHistory} for - * tethering traffic. - * - * @hide - */ - public static final int UID_TETHERING = NetworkStats.UID_TETHERING; - - /** - * Tag values in this range are reserved for the network stack. The network stack is - * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline - * module separate process, and as the system UID otherwise. - */ - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00; - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF; - - /** - * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services - * like DownloadManager when performing traffic on behalf of an application. - */ - // Please note there is no enforcement of these constants, so do not rely on them to - // determine that the caller is a system caller. - /** @hide */ - @SystemApi - public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00; - /** @hide */ - @SystemApi - public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F; - - /** - * Tag values between these ranges are reserved for the network stack to do traffic - * on behalf of applications. It is a subrange of the range above. - */ - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80; - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F; - - /** - * Default tag value for {@link DownloadManager} traffic. - * - * @hide - */ - public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFFFF01; - - /** - * Default tag value for {@link MediaPlayer} traffic. - * - * @hide - */ - public static final int TAG_SYSTEM_MEDIA = 0xFFFFFF02; - - /** - * Default tag value for {@link BackupManager} backup traffic; that is, - * traffic from the device to the storage backend. - * - * @hide - */ - public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; - - /** - * Default tag value for {@link BackupManager} restore traffic; that is, - * app data retrieved from the storage backend at install time. - * - * @hide - */ - public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04; - - /** - * Default tag value for code (typically APKs) downloaded by an app store on - * behalf of the app, such as updates. - * - * @hide - */ - public static final int TAG_SYSTEM_APP = 0xFFFFFF05; - - // TODO : remove this constant when Wifi code is updated - /** @hide */ - public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; - - private static INetworkStatsService sStatsService; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - private synchronized static INetworkStatsService getStatsService() { - if (sStatsService == null) { - throw new IllegalStateException("TrafficStats not initialized, uid=" - + Binder.getCallingUid()); - } - return sStatsService; - } - - /** - * Snapshot of {@link NetworkStats} when the currently active profiling - * session started, or {@code null} if no session active. - * - * @see #startDataProfiling(Context) - * @see #stopDataProfiling(Context) - */ - private static NetworkStats sActiveProfilingStart; - - private static Object sProfilingLock = new Object(); - - private static final String LOOPBACK_IFACE = "lo"; - - /** - * Initialization {@link TrafficStats} with the context, to - * allow {@link TrafficStats} to fetch the needed binder. - * - * @param context a long-lived context, such as the application context or system - * server context. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @SuppressLint("VisiblySynchronized") - public static synchronized void init(@NonNull final Context context) { - if (sStatsService != null) { - throw new IllegalStateException("TrafficStats is already initialized, uid=" - + Binder.getCallingUid()); - } - final NetworkStatsManager statsManager = - context.getSystemService(NetworkStatsManager.class); - if (statsManager == null) { - // TODO: Currently Process.isSupplemental is not working yet, because it depends on - // process to run in a certain UID range, which is not true for now. Change this - // to Log.wtf once Process.isSupplemental is ready. - Log.e(TAG, "TrafficStats not initialized, uid=" + Binder.getCallingUid()); - return; - } - sStatsService = statsManager.getBinder(); - } - - /** - * Attach the socket tagger implementation to the current process, to - * get notified when a socket's {@link FileDescriptor} is assigned to - * a thread. See {@link SocketTagger#set(SocketTagger)}. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static void attachSocketTagger() { - dalvik.system.SocketTagger.set(new SocketTagger()); - } - - private static class SocketTagger extends dalvik.system.SocketTagger { - - // TODO: set to false - private static final boolean LOGD = true; - - SocketTagger() { - } - - @Override - public void tag(FileDescriptor fd) throws SocketException { - final UidTag tagInfo = sThreadUidTag.get(); - if (LOGD) { - Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" - + Integer.toHexString(tagInfo.tag) + ", statsUid=" + tagInfo.uid); - } - if (tagInfo.tag == -1) { - StrictMode.noteUntaggedSocket(); - } - - if (tagInfo.tag == -1 && tagInfo.uid == -1) return; - final int errno = native_tagSocketFd(fd, tagInfo.tag, tagInfo.uid); - if (errno < 0) { - Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " - + tagInfo.tag + ", " - + tagInfo.uid + ") failed with errno" + errno); - } - } - - @Override - public void untag(FileDescriptor fd) throws SocketException { - if (LOGD) { - Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); - } - - final UidTag tagInfo = sThreadUidTag.get(); - if (tagInfo.tag == -1 && tagInfo.uid == -1) return; - - final int errno = native_untagSocketFd(fd); - if (errno < 0) { - Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); - } - } - } - - private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); - private static native int native_untagSocketFd(FileDescriptor fd); - - private static class UidTag { - public int tag = -1; - public int uid = -1; - } - - private static ThreadLocal<UidTag> sThreadUidTag = new ThreadLocal<UidTag>() { - @Override - protected UidTag initialValue() { - return new UidTag(); - } - }; - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - * <p> - * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - * <p> - * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and - * used internally by system services like {@link DownloadManager} when - * performing traffic on behalf of an application. - * - * @see #clearThreadStatsTag() - */ - public static void setThreadStatsTag(int tag) { - getAndSetThreadStatsTag(tag); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - * <p> - * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - * <p> - * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and - * used internally by system services like {@link DownloadManager} when - * performing traffic on behalf of an application. - * - * @return the current tag for the calling thread, which can be used to - * restore any existing values after a nested operation is finished - */ - public static int getAndSetThreadStatsTag(int tag) { - final int old = sThreadUidTag.get().tag; - sThreadUidTag.get().tag = tag; - return old; - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all backup-related traffic. - * - * @hide - */ - @SystemApi - public static void setThreadStatsTagBackup() { - setThreadStatsTag(TAG_SYSTEM_BACKUP); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all restore-related traffic. - * - * @hide - */ - @SystemApi - public static void setThreadStatsTagRestore() { - setThreadStatsTag(TAG_SYSTEM_RESTORE); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all code (typically APKs) downloaded by an app store on - * behalf of the app, such as updates. - * - * @hide - */ - @SystemApi - public static void setThreadStatsTagApp() { - setThreadStatsTag(TAG_SYSTEM_APP); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all download provider traffic. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static void setThreadStatsTagDownload() { - setThreadStatsTag(TAG_SYSTEM_DOWNLOAD); - } - - /** - * Get the active tag used when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - * {@link #tagSocket(Socket)}. - * - * @see #setThreadStatsTag(int) - */ - public static int getThreadStatsTag() { - return sThreadUidTag.get().tag; - } - - /** - * Clear any active tag set to account {@link Socket} traffic originating - * from the current thread. - * - * @see #setThreadStatsTag(int) - */ - public static void clearThreadStatsTag() { - sThreadUidTag.get().tag = -1; - } - - /** - * Set specific UID to use when accounting {@link Socket} traffic - * originating from the current thread. Designed for use when performing an - * operation on behalf of another application, or when another application - * is performing operations on your behalf. - * <p> - * Any app can <em>accept</em> blame for traffic performed on a socket - * originally created by another app by calling this method with the - * {@link android.system.Os#getuid()} value. However, only apps holding the - * {@code android.Manifest.permission#UPDATE_DEVICE_STATS} permission may - * <em>assign</em> blame to another UIDs. - * <p> - * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - */ - @SuppressLint("RequiresPermission") - public static void setThreadStatsUid(int uid) { - sThreadUidTag.get().uid = uid; - } - - /** - * Get the active UID used when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - * {@link #tagSocket(Socket)}. - * - * @see #setThreadStatsUid(int) - */ - public static int getThreadStatsUid() { - return sThreadUidTag.get().uid; - } - - /** - * Set specific UID to use when accounting {@link Socket} traffic - * originating from the current thread as the calling UID. Designed for use - * when another application is performing operations on your behalf. - * <p> - * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - * - * @removed - * @deprecated use {@link #setThreadStatsUid(int)} instead. - */ - @Deprecated - public static void setThreadStatsUidSelf() { - setThreadStatsUid(android.os.Process.myUid()); - } - - /** - * Clear any active UID set to account {@link Socket} traffic originating - * from the current thread. - * - * @see #setThreadStatsUid(int) - */ - @SuppressLint("RequiresPermission") - public static void clearThreadStatsUid() { - setThreadStatsUid(-1); - } - - /** - * Tag the given {@link Socket} with any statistics parameters active for - * the current thread. Subsequent calls always replace any existing - * parameters. When finished, call {@link #untagSocket(Socket)} to remove - * statistics parameters. - * - * @see #setThreadStatsTag(int) - */ - public static void tagSocket(@NonNull Socket socket) throws SocketException { - SocketTagger.get().tag(socket); - } - - /** - * Remove any statistics parameters from the given {@link Socket}. - * <p> - * In Android 8.1 (API level 27) and lower, a socket is automatically - * untagged when it's sent to another process using binder IPC with a - * {@code ParcelFileDescriptor} container. In Android 9.0 (API level 28) - * and higher, the socket tag is kept when the socket is sent to another - * process using binder IPC. You can mimic the previous behavior by - * calling {@code untagSocket()} before sending the socket to another - * process. - */ - public static void untagSocket(@NonNull Socket socket) throws SocketException { - SocketTagger.get().untag(socket); - } - - /** - * Tag the given {@link DatagramSocket} with any statistics parameters - * active for the current thread. Subsequent calls always replace any - * existing parameters. When finished, call - * {@link #untagDatagramSocket(DatagramSocket)} to remove statistics - * parameters. - * - * @see #setThreadStatsTag(int) - */ - public static void tagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException { - SocketTagger.get().tag(socket); - } - - /** - * Remove any statistics parameters from the given {@link DatagramSocket}. - */ - public static void untagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException { - SocketTagger.get().untag(socket); - } - - /** - * Tag the given {@link FileDescriptor} socket with any statistics - * parameters active for the current thread. Subsequent calls always replace - * any existing parameters. When finished, call - * {@link #untagFileDescriptor(FileDescriptor)} to remove statistics - * parameters. - * - * @see #setThreadStatsTag(int) - */ - public static void tagFileDescriptor(@NonNull FileDescriptor fd) throws IOException { - SocketTagger.get().tag(fd); - } - - /** - * Remove any statistics parameters from the given {@link FileDescriptor} - * socket. - */ - public static void untagFileDescriptor(@NonNull FileDescriptor fd) throws IOException { - SocketTagger.get().untag(fd); - } - - /** - * Start profiling data usage for current UID. Only one profiling session - * can be active at a time. - * - * @hide - */ - public static void startDataProfiling(Context context) { - synchronized (sProfilingLock) { - if (sActiveProfilingStart != null) { - throw new IllegalStateException("already profiling data"); - } - - // take snapshot in time; we calculate delta later - sActiveProfilingStart = getDataLayerSnapshotForUid(context); - } - } - - /** - * Stop profiling data usage for current UID. - * - * @return Detailed {@link NetworkStats} of data that occurred since last - * {@link #startDataProfiling(Context)} call. - * @hide - */ - public static NetworkStats stopDataProfiling(Context context) { - synchronized (sProfilingLock) { - if (sActiveProfilingStart == null) { - throw new IllegalStateException("not profiling data"); - } - - // subtract starting values and return delta - final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); - final NetworkStats profilingDelta = NetworkStats.subtract( - profilingStop, sActiveProfilingStart, null, null); - sActiveProfilingStart = null; - return profilingDelta; - } - } - - /** - * Increment count of network operations performed under the accounting tag - * currently active on the calling thread. This can be used to derive - * bytes-per-operation. - * - * @param operationCount Number of operations to increment count by. - */ - public static void incrementOperationCount(int operationCount) { - final int tag = getThreadStatsTag(); - incrementOperationCount(tag, operationCount); - } - - /** - * Increment count of network operations performed under the given - * accounting tag. This can be used to derive bytes-per-operation. - * - * @param tag Accounting tag used in {@link #setThreadStatsTag(int)}. - * @param operationCount Number of operations to increment count by. - */ - public static void incrementOperationCount(int tag, int operationCount) { - final int uid = android.os.Process.myUid(); - try { - getStatsService().incrementOperationCount(uid, tag, operationCount); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - public static void closeQuietly(INetworkStatsSession session) { - // TODO: move to NetworkStatsService once it exists - if (session != null) { - try { - session.close(); - } catch (RuntimeException rethrown) { - throw rethrown; - } catch (Exception ignored) { - } - } - } - - private static long addIfSupported(long stat) { - return (stat == UNSUPPORTED) ? 0 : stat; - } - - /** - * Return number of packets transmitted across mobile networks since device - * boot. Counts packets across all mobile network interfaces, and always - * increases monotonically since device boot. Statistics are measured at the - * network layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileTxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getTxPackets(iface)); - } - return total; - } - - /** - * Return number of packets received across mobile networks since device - * boot. Counts packets across all mobile network interfaces, and always - * increases monotonically since device boot. Statistics are measured at the - * network layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileRxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getRxPackets(iface)); - } - return total; - } - - /** - * Return number of bytes transmitted across mobile networks since device - * boot. Counts packets across all mobile network interfaces, and always - * increases monotonically since device boot. Statistics are measured at the - * network layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileTxBytes() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getTxBytes(iface)); - } - return total; - } - - /** - * Return number of bytes received across mobile networks since device boot. - * Counts packets across all mobile network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileRxBytes() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getRxBytes(iface)); - } - return total; - } - - /** {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static long getMobileTcpRxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - long stat = UNSUPPORTED; - try { - stat = getStatsService().getIfaceStats(iface, TYPE_TCP_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - total += addIfSupported(stat); - } - return total; - } - - /** {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static long getMobileTcpTxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - long stat = UNSUPPORTED; - try { - stat = getStatsService().getIfaceStats(iface, TYPE_TCP_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - total += addIfSupported(stat); - } - return total; - } - - /** - * Return the number of packets transmitted on the specified interface since the interface - * was created. Statistics are measured at the network layer, so both TCP and - * UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of transmitted packets. - */ - public static long getTxPackets(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the number of packets received on the specified interface since the interface was - * created. Statistics are measured at the network layer, so both TCP - * and UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of received packets. - */ - public static long getRxPackets(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the number of bytes transmitted on the specified interface since the interface - * was created. Statistics are measured at the network layer, so both TCP and - * UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of transmitted bytes. - */ - public static long getTxBytes(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the number of bytes received on the specified interface since the interface - * was created. Statistics are measured at the network layer, so both TCP - * and UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of received bytes. - */ - public static long getRxBytes(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackTxPackets() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackRxPackets() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackTxBytes() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackRxBytes() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets transmitted since device boot. Counts packets - * across all network interfaces, and always increases monotonically since - * device boot. Statistics are measured at the network layer, so they - * include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalTxPackets() { - try { - return getStatsService().getTotalStats(TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets received since device boot. Counts packets - * across all network interfaces, and always increases monotonically since - * device boot. Statistics are measured at the network layer, so they - * include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalRxPackets() { - try { - return getStatsService().getTotalStats(TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes transmitted since device boot. Counts packets - * across all network interfaces, and always increases monotonically since - * device boot. Statistics are measured at the network layer, so they - * include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalTxBytes() { - try { - return getStatsService().getTotalStats(TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes received since device boot. Counts packets across - * all network interfaces, and always increases monotonically since device - * boot. Statistics are measured at the network layer, so they include both - * TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalRxBytes() { - try { - return getStatsService().getTotalStats(TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes transmitted by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - * <p> - * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidTxBytes(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes received by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. - * <p> - * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidRxBytes(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets transmitted by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. - * <p> - * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidTxPackets(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets received by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - * <p> - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. - * <p> - * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidRxPackets(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxBytes(int) - */ - @Deprecated - public static long getUidTcpTxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxBytes(int) - */ - @Deprecated - public static long getUidTcpRxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxBytes(int) - */ - @Deprecated - public static long getUidUdpTxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxBytes(int) - */ - @Deprecated - public static long getUidUdpRxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxPackets(int) - */ - @Deprecated - public static long getUidTcpTxSegments(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxPackets(int) - */ - @Deprecated - public static long getUidTcpRxSegments(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxPackets(int) - */ - @Deprecated - public static long getUidUdpTxPackets(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxPackets(int) - */ - @Deprecated - public static long getUidUdpRxPackets(int uid) { - return UNSUPPORTED; - } - - /** - * Return detailed {@link NetworkStats} for the current UID. Requires no - * special permission. - */ - private static NetworkStats getDataLayerSnapshotForUid(Context context) { - // TODO: take snapshot locally, since proc file is now visible - final int uid = android.os.Process.myUid(); - try { - return getStatsService().getDataLayerSnapshotForUid(uid); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return set of any ifaces associated with mobile networks since boot. - * Interfaces are never removed from this list, so counters should always be - * monotonic. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - private static String[] getMobileIfaces() { - try { - return getStatsService().getMobileIfaces(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - // NOTE: keep these in sync with {@code com_android_server_net_NetworkStatsService.cpp}. - /** {@hide} */ - public static final int TYPE_RX_BYTES = 0; - /** {@hide} */ - public static final int TYPE_RX_PACKETS = 1; - /** {@hide} */ - public static final int TYPE_TX_BYTES = 2; - /** {@hide} */ - public static final int TYPE_TX_PACKETS = 3; - /** {@hide} */ - public static final int TYPE_TCP_RX_PACKETS = 4; - /** {@hide} */ - public static final int TYPE_TCP_TX_PACKETS = 5; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl b/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl deleted file mode 100644 index a56f2f40583b..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -parcelable UnderlyingNetworkInfo; diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java b/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java deleted file mode 100644 index 7ab53b1da856..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * A lightweight container used to carry information on the networks that underly a given - * virtual network. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class UnderlyingNetworkInfo implements Parcelable { - /** The owner of this network. */ - private final int mOwnerUid; - - /** The interface name of this network. */ - @NonNull - private final String mIface; - - /** The names of the interfaces underlying this network. */ - @NonNull - private final List<String> mUnderlyingIfaces; - - public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface, - @NonNull List<String> underlyingIfaces) { - Objects.requireNonNull(iface); - Objects.requireNonNull(underlyingIfaces); - mOwnerUid = ownerUid; - mIface = iface; - mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); - } - - private UnderlyingNetworkInfo(@NonNull Parcel in) { - mOwnerUid = in.readInt(); - mIface = in.readString(); - List<String> underlyingIfaces = new ArrayList<>(); - in.readList(underlyingIfaces, null /*classLoader*/, java.lang.String.class); - mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); - } - - /** Get the owner of this network. */ - public int getOwnerUid() { - return mOwnerUid; - } - - /** Get the interface name of this network. */ - @NonNull - public String getInterface() { - return mIface; - } - - /** Get the names of the interfaces underlying this network. */ - @NonNull - public List<String> getUnderlyingInterfaces() { - return mUnderlyingIfaces; - } - - @Override - public String toString() { - return "UnderlyingNetworkInfo{" - + "ownerUid=" + mOwnerUid - + ", iface='" + mIface + '\'' - + ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\'' - + '}'; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mOwnerUid); - dest.writeString(mIface); - dest.writeList(mUnderlyingIfaces); - } - - @NonNull - public static final Parcelable.Creator<UnderlyingNetworkInfo> CREATOR = - new Parcelable.Creator<UnderlyingNetworkInfo>() { - @NonNull - @Override - public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) { - return new UnderlyingNetworkInfo(in); - } - - @NonNull - @Override - public UnderlyingNetworkInfo[] newArray(int size) { - return new UnderlyingNetworkInfo[size]; - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof UnderlyingNetworkInfo)) return false; - final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; - return mOwnerUid == that.getOwnerUid() - && Objects.equals(mIface, that.getInterface()) - && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces()); - } - - @Override - public int hashCode() { - return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl deleted file mode 100644 index 4e8a5b23093a..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.netstats; - -import android.net.DataUsageRequest; - -/** - * Interface for NetworkStatsService to notify events to the callers of registerUsageCallback. - * - * @hide - */ -oneway interface IUsageCallback { - void onThresholdReached(in DataUsageRequest request); - void onCallbackReleased(in DataUsageRequest request); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl deleted file mode 100644 index 74c3ba44b69e..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl +++ /dev/null @@ -1,28 +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.net.netstats.provider; - -/** - * Interface for NetworkStatsService to query network statistics and set data limits. - * - * @hide - */ -oneway interface INetworkStatsProvider { - void onRequestStatsUpdate(int token); - void onSetAlert(long quotaBytes); - void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl deleted file mode 100644 index 01ff02dfc5b3..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ /dev/null @@ -1,32 +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.net.netstats.provider; - -import android.net.NetworkStats; - -/** - * Interface for implementor of {@link INetworkStatsProviderCallback} to push events - * such as network statistics update or notify limit reached. - * @hide - */ -oneway interface INetworkStatsProviderCallback { - void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); - void notifyAlertReached(); - void notifyWarningReached(); - void notifyLimitReached(); - void unregister(); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java deleted file mode 100644 index d37a53dbf1e9..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java +++ /dev/null @@ -1,232 +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.net.netstats.provider; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.net.NetworkStats; -import android.os.RemoteException; - -/** - * A base class that allows external modules to implement a custom network statistics provider. - * @hide - */ -@SystemApi -public abstract class NetworkStatsProvider { - /** - * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit} - * indicates there is no limit. - */ - public static final int QUOTA_UNLIMITED = -1; - - @NonNull private final INetworkStatsProvider mProviderBinder = - new INetworkStatsProvider.Stub() { - - @Override - public void onRequestStatsUpdate(int token) { - NetworkStatsProvider.this.onRequestStatsUpdate(token); - } - - @Override - public void onSetAlert(long quotaBytes) { - NetworkStatsProvider.this.onSetAlert(quotaBytes); - } - - @Override - public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) { - NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes); - } - }; - - // The binder given by the service when successfully registering. Only null before registering, - // never null once non-null. - @Nullable - private INetworkStatsProviderCallback mProviderCbBinder; - - /** - * Return the binder invoked by the service and redirect function calls to the overridden - * methods. - * @hide - */ - @NonNull - public INetworkStatsProvider getProviderBinder() { - return mProviderBinder; - } - - /** - * Store the binder that was returned by the service when successfully registering. Note that - * the provider cannot be re-registered. Hence this method can only be called once per provider. - * - * @hide - */ - public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) { - if (mProviderCbBinder != null) { - throw new IllegalArgumentException("provider is already registered"); - } - mProviderCbBinder = binder; - } - - /** - * Get the binder that was returned by the service when successfully registering. Or null if the - * provider was never registered. - * - * @hide - */ - @Nullable - public INetworkStatsProviderCallback getProviderCallbackBinder() { - return mProviderCbBinder; - } - - /** - * Get the binder that was returned by the service when successfully registering. Throw an - * {@link IllegalStateException} if the provider is not registered. - * - * @hide - */ - @NonNull - public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() { - if (mProviderCbBinder == null) { - throw new IllegalStateException("the provider is not registered"); - } - return mProviderCbBinder; - } - - /** - * Notify the system of new network statistics. - * - * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must - * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)} - * being called. Responding later increases the probability stats will be dropped. The - * provider can also call this whenever it wants to reports new stats for any reason. - * Note that the system will not necessarily immediately propagate the statistics to - * reflect the update. - * - * @param token the token under which these stats were gathered. Providers can call this method - * with the current token as often as they want, until the token changes. - * {@see NetworkStatsProvider#onRequestStatsUpdate()} - * @param ifaceStats the {@link NetworkStats} per interface to be reported. - * The provider should not include any traffic that is already counted by - * kernel interface counters. - * @param uidStats the same stats as above, but counts {@link NetworkStats} - * per uid. - */ - public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, - @NonNull NetworkStats uidStats) { - try { - getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the quota set by {@code onSetAlert} has been reached. - */ - public void notifyAlertReached() { - try { - getProviderCallbackBinderOrThrow().notifyAlertReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. - */ - public void notifyWarningReached() { - try { - // Reuse the code path to notify warning reached with limit reached - // since framework handles them in the same way. - getProviderCallbackBinderOrThrow().notifyWarningReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the limit set by {@link #onSetLimit} or limit set by - * {@link #onSetWarningAndLimit} has been reached. - */ - public void notifyLimitReached() { - try { - getProviderCallbackBinderOrThrow().notifyLimitReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Called by {@code NetworkStatsService} when it requires to know updated stats. - * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible. - * Responding later increases the probability stats will be dropped. Memory allowing, the - * system will try to take stats into account up to one minute after calling - * {@link #onRequestStatsUpdate}. - * - * @param token a positive number identifying the new state of the system under which - * {@link NetworkStats} have to be gathered from now on. When this is called, - * custom implementations of providers MUST tally and report the latest stats with - * the previous token, under which stats were being gathered so far. - */ - public abstract void onRequestStatsUpdate(int token); - - /** - * Called by {@code NetworkStatsService} when setting the interface quota for the specified - * upstream interface. When this is called, the custom implementation should block all egress - * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have - * been reached, and MUST respond to it by calling - * {@link NetworkStatsProvider#notifyLimitReached()}. - * - * @param iface the interface requiring the operation. - * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - */ - public abstract void onSetLimit(@NonNull String iface, long quotaBytes); - - /** - * Called by {@code NetworkStatsService} when setting the interface quotas for the specified - * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system - * will not call {@link #onSetLimit}. When this method is called, the implementation - * should behave as follows: - * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on - * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}. - * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on - * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}. - * - * @param iface the interface requiring the operation. - * @param warningBytes the warning defined as the number of bytes, starting from zero and - * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates - * there is no warning. - * @param limitBytes the limit defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - */ - public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { - // Backward compatibility for those who didn't override this function. - onSetLimit(iface, limitBytes); - } - - /** - * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations - * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes - * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should - * not block all egress packets. - * - * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. - */ - public abstract void onSetAlert(long quotaBytes); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl deleted file mode 100644 index 89e9cdbd4445..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl +++ /dev/null @@ -1,30 +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.net.nsd; - -import android.net.nsd.INsdManagerCallback; -import android.net.nsd.INsdServiceConnector; -import android.os.Messenger; - -/** - * Interface that NsdService implements to connect NsdManager clients. - * - * {@hide} - */ -interface INsdManager { - INsdServiceConnector connect(INsdManagerCallback cb); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl deleted file mode 100644 index 1a262ec0e9dd..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl +++ /dev/null @@ -1,39 +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.net.nsd; - -import android.os.Messenger; -import android.net.nsd.NsdServiceInfo; - -/** - * Callbacks from NsdService to NsdManager - * @hide - */ -oneway interface INsdManagerCallback { - void onDiscoverServicesStarted(int listenerKey, in NsdServiceInfo info); - void onDiscoverServicesFailed(int listenerKey, int error); - void onServiceFound(int listenerKey, in NsdServiceInfo info); - void onServiceLost(int listenerKey, in NsdServiceInfo info); - void onStopDiscoveryFailed(int listenerKey, int error); - void onStopDiscoverySucceeded(int listenerKey); - void onRegisterServiceFailed(int listenerKey, int error); - void onRegisterServiceSucceeded(int listenerKey, in NsdServiceInfo info); - void onUnregisterServiceFailed(int listenerKey, int error); - void onUnregisterServiceSucceeded(int listenerKey); - void onResolveServiceFailed(int listenerKey, int error); - void onResolveServiceSucceeded(int listenerKey, in NsdServiceInfo info); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl deleted file mode 100644 index b06ae55b150e..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl +++ /dev/null @@ -1,35 +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.net.nsd; - -import android.net.nsd.INsdManagerCallback; -import android.net.nsd.NsdServiceInfo; -import android.os.Messenger; - -/** - * Interface that NsdService implements for each NsdManager client. - * - * {@hide} - */ -interface INsdServiceConnector { - void registerService(int listenerKey, in NsdServiceInfo serviceInfo); - void unregisterService(int listenerKey); - void discoverServices(int listenerKey, in NsdServiceInfo serviceInfo); - void stopDiscovery(int listenerKey); - void resolveService(int listenerKey, in NsdServiceInfo serviceInfo); - void startDaemon(); -}
\ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java deleted file mode 100644 index 209f372fd377..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java +++ /dev/null @@ -1,1083 +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.net.nsd; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SystemService; -import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.NetworkRequest; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.Objects; -import java.util.concurrent.Executor; - -/** - * The Network Service Discovery Manager class provides the API to discover services - * on a network. As an example, if device A and device B are connected over a Wi-Fi - * network, a game registered on device A can be discovered by a game on device - * B. Another example use case is an application discovering printers on the network. - * - * <p> The API currently supports DNS based service discovery and discovery is currently - * limited to a local network over Multicast DNS. DNS service discovery is described at - * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt - * - * <p> The API is asynchronous, and responses to requests from an application are on listener - * callbacks on a separate internal thread. - * - * <p> There are three main operations the API supports - registration, discovery and resolution. - * <pre> - * Application start - * | - * | - * | onServiceRegistered() - * Register any local services / - * to be advertised with \ - * registerService() onRegistrationFailed() - * | - * | - * discoverServices() - * | - * Maintain a list to track - * discovered services - * | - * |---------> - * | | - * | onServiceFound() - * | | - * | add service to list - * | | - * |<---------- - * | - * |---------> - * | | - * | onServiceLost() - * | | - * | remove service from list - * | | - * |<---------- - * | - * | - * | Connect to a service - * | from list ? - * | - * resolveService() - * | - * onServiceResolved() - * | - * Establish connection to service - * with the host and port information - * - * </pre> - * An application that needs to advertise itself over a network for other applications to - * discover it can do so with a call to {@link #registerService}. If Example is a http based - * application that can provide HTML data to peer services, it can register a name "Example" - * with service type "_http._tcp". A successful registration is notified with a callback to - * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified - * over {@link RegistrationListener#onRegistrationFailed} - * - * <p> A peer application looking for http services can initiate a discovery for "_http._tcp" - * with a call to {@link #discoverServices}. A service found is notified with a callback - * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on - * {@link DiscoveryListener#onServiceLost}. - * - * <p> Once the peer application discovers the "Example" http service, and either needs to read the - * attributes of the service or wants to receive data from the "Example" application, it can - * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port - * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a - * failure is notified on {@link ResolveListener#onResolveFailed}. - * - * Applications can reserve for a service type at - * http://www.iana.org/form/ports-service. Existing services can be found at - * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml - * - * {@see NsdServiceInfo} - */ -@SystemService(Context.NSD_SERVICE) -public final class NsdManager { - private static final String TAG = NsdManager.class.getSimpleName(); - private static final boolean DBG = false; - - /** - * When enabled, apps targeting < Android 12 are considered legacy for - * the NSD native daemon. - * The platform will only keep the daemon running as long as there are - * any legacy apps connected. - * - * After Android 12, directly communicate with native daemon might not - * work since the native damon won't always stay alive. - * Use the NSD APIs from NsdManager as the replacement is recommended. - * An another alternative could be bundling your own mdns solutions instead of - * depending on the system mdns native daemon. - * - * @hide - */ - @ChangeId - @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S) - public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS = 191844585L; - - /** - * Broadcast intent action to indicate whether network service discovery is - * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state - * information as int. - * - * @see #EXTRA_NSD_STATE - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED"; - - /** - * The lookup key for an int that indicates whether network service discovery is enabled - * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}. - * - * @see #NSD_STATE_DISABLED - * @see #NSD_STATE_ENABLED - */ - public static final String EXTRA_NSD_STATE = "nsd_state"; - - /** - * Network service discovery is disabled - * - * @see #ACTION_NSD_STATE_CHANGED - */ - public static final int NSD_STATE_DISABLED = 1; - - /** - * Network service discovery is enabled - * - * @see #ACTION_NSD_STATE_CHANGED - */ - public static final int NSD_STATE_ENABLED = 2; - - /** @hide */ - public static final int DISCOVER_SERVICES = 1; - /** @hide */ - public static final int DISCOVER_SERVICES_STARTED = 2; - /** @hide */ - public static final int DISCOVER_SERVICES_FAILED = 3; - /** @hide */ - public static final int SERVICE_FOUND = 4; - /** @hide */ - public static final int SERVICE_LOST = 5; - - /** @hide */ - public static final int STOP_DISCOVERY = 6; - /** @hide */ - public static final int STOP_DISCOVERY_FAILED = 7; - /** @hide */ - public static final int STOP_DISCOVERY_SUCCEEDED = 8; - - /** @hide */ - public static final int REGISTER_SERVICE = 9; - /** @hide */ - public static final int REGISTER_SERVICE_FAILED = 10; - /** @hide */ - public static final int REGISTER_SERVICE_SUCCEEDED = 11; - - /** @hide */ - public static final int UNREGISTER_SERVICE = 12; - /** @hide */ - public static final int UNREGISTER_SERVICE_FAILED = 13; - /** @hide */ - public static final int UNREGISTER_SERVICE_SUCCEEDED = 14; - - /** @hide */ - public static final int RESOLVE_SERVICE = 15; - /** @hide */ - public static final int RESOLVE_SERVICE_FAILED = 16; - /** @hide */ - public static final int RESOLVE_SERVICE_SUCCEEDED = 17; - - /** @hide */ - public static final int DAEMON_CLEANUP = 18; - - /** @hide */ - public static final int DAEMON_STARTUP = 19; - - /** @hide */ - public static final int ENABLE = 20; - /** @hide */ - public static final int DISABLE = 21; - - /** @hide */ - public static final int NATIVE_DAEMON_EVENT = 22; - - /** @hide */ - public static final int REGISTER_CLIENT = 23; - /** @hide */ - public static final int UNREGISTER_CLIENT = 24; - - /** Dns based service discovery protocol */ - public static final int PROTOCOL_DNS_SD = 0x0001; - - private static final SparseArray<String> EVENT_NAMES = new SparseArray<>(); - static { - EVENT_NAMES.put(DISCOVER_SERVICES, "DISCOVER_SERVICES"); - EVENT_NAMES.put(DISCOVER_SERVICES_STARTED, "DISCOVER_SERVICES_STARTED"); - EVENT_NAMES.put(DISCOVER_SERVICES_FAILED, "DISCOVER_SERVICES_FAILED"); - EVENT_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND"); - EVENT_NAMES.put(SERVICE_LOST, "SERVICE_LOST"); - EVENT_NAMES.put(STOP_DISCOVERY, "STOP_DISCOVERY"); - EVENT_NAMES.put(STOP_DISCOVERY_FAILED, "STOP_DISCOVERY_FAILED"); - EVENT_NAMES.put(STOP_DISCOVERY_SUCCEEDED, "STOP_DISCOVERY_SUCCEEDED"); - EVENT_NAMES.put(REGISTER_SERVICE, "REGISTER_SERVICE"); - EVENT_NAMES.put(REGISTER_SERVICE_FAILED, "REGISTER_SERVICE_FAILED"); - EVENT_NAMES.put(REGISTER_SERVICE_SUCCEEDED, "REGISTER_SERVICE_SUCCEEDED"); - EVENT_NAMES.put(UNREGISTER_SERVICE, "UNREGISTER_SERVICE"); - EVENT_NAMES.put(UNREGISTER_SERVICE_FAILED, "UNREGISTER_SERVICE_FAILED"); - EVENT_NAMES.put(UNREGISTER_SERVICE_SUCCEEDED, "UNREGISTER_SERVICE_SUCCEEDED"); - EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE"); - EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED"); - EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED"); - EVENT_NAMES.put(DAEMON_CLEANUP, "DAEMON_CLEANUP"); - EVENT_NAMES.put(DAEMON_STARTUP, "DAEMON_STARTUP"); - EVENT_NAMES.put(ENABLE, "ENABLE"); - EVENT_NAMES.put(DISABLE, "DISABLE"); - EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT"); - } - - /** @hide */ - public static String nameOf(int event) { - String name = EVENT_NAMES.get(event); - if (name == null) { - return Integer.toString(event); - } - return name; - } - - private static final int FIRST_LISTENER_KEY = 1; - - private final INsdServiceConnector mService; - private final Context mContext; - - private int mListenerKey = FIRST_LISTENER_KEY; - @GuardedBy("mMapLock") - private final SparseArray mListenerMap = new SparseArray(); - @GuardedBy("mMapLock") - private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>(); - @GuardedBy("mMapLock") - private final SparseArray<Executor> mExecutorMap = new SparseArray<>(); - private final Object mMapLock = new Object(); - // Map of listener key sent by client -> per-network discovery tracker - @GuardedBy("mPerNetworkDiscoveryMap") - private final ArrayMap<Integer, PerNetworkDiscoveryTracker> - mPerNetworkDiscoveryMap = new ArrayMap<>(); - - private final ServiceHandler mHandler; - - private class PerNetworkDiscoveryTracker { - final String mServiceType; - final int mProtocolType; - final DiscoveryListener mBaseListener; - final Executor mBaseExecutor; - final ArrayMap<Network, DelegatingDiscoveryListener> mPerNetworkListeners = - new ArrayMap<>(); - - final NetworkCallback mNetworkCb = new NetworkCallback() { - @Override - public void onAvailable(@NonNull Network network) { - final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener( - network, mBaseListener); - mPerNetworkListeners.put(network, wrappedListener); - discoverServices(mServiceType, mProtocolType, network, mBaseExecutor, - wrappedListener); - } - - @Override - public void onLost(@NonNull Network network) { - final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network); - if (listener == null) return; - listener.notifyAllServicesLost(); - // Listener will be removed from map in discovery stopped callback - stopServiceDiscovery(listener); - } - }; - - // Accessed from mHandler - private boolean mStopRequested; - - public void start(@NonNull NetworkRequest request) { - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - cm.registerNetworkCallback(request, mNetworkCb, mHandler); - mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType)); - } - - /** - * Stop discovery on all networks tracked by this class. - * - * This will request all underlying listeners to stop, and the last one to stop will call - * onDiscoveryStopped or onStopDiscoveryFailed. - * - * Must be called on the handler thread. - */ - public void requestStop() { - mHandler.post(() -> { - mStopRequested = true; - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - cm.unregisterNetworkCallback(mNetworkCb); - if (mPerNetworkListeners.size() == 0) { - mBaseListener.onDiscoveryStopped(mServiceType); - return; - } - for (int i = 0; i < mPerNetworkListeners.size(); i++) { - final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i); - stopServiceDiscovery(listener); - } - }); - } - - private PerNetworkDiscoveryTracker(String serviceType, int protocolType, - Executor baseExecutor, DiscoveryListener baseListener) { - mServiceType = serviceType; - mProtocolType = protocolType; - mBaseExecutor = baseExecutor; - mBaseListener = baseListener; - } - - /** - * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a - * network is lost. - * - * Service lost notifications only contain service name, type and network, so only track - * that information (Network is known from the listener). This also implements - * equals/hashCode for usage in maps. - */ - private class TrackedNsdInfo { - private final String mServiceName; - private final String mServiceType; - TrackedNsdInfo(NsdServiceInfo info) { - mServiceName = info.getServiceName(); - mServiceType = info.getServiceType(); - } - - @Override - public int hashCode() { - return Objects.hash(mServiceName, mServiceType); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TrackedNsdInfo)) return false; - final TrackedNsdInfo other = (TrackedNsdInfo) obj; - return Objects.equals(mServiceName, other.mServiceName) - && Objects.equals(mServiceType, other.mServiceType); - } - } - - private class DelegatingDiscoveryListener implements DiscoveryListener { - private final Network mNetwork; - private final DiscoveryListener mWrapped; - private final ArraySet<TrackedNsdInfo> mFoundInfo = new ArraySet<>(); - - private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) { - mNetwork = network; - mWrapped = listener; - } - - void notifyAllServicesLost() { - for (int i = 0; i < mFoundInfo.size(); i++) { - final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i); - final NsdServiceInfo serviceInfo = new NsdServiceInfo( - trackedInfo.mServiceName, trackedInfo.mServiceType); - serviceInfo.setNetwork(mNetwork); - mWrapped.onServiceLost(serviceInfo); - } - } - - @Override - public void onStartDiscoveryFailed(String serviceType, int errorCode) { - // The delegated listener is used when NsdManager takes care of starting/stopping - // discovery on multiple networks. Failure to start on one network is not a global - // failure to be reported up, as other networks may succeed: just log. - Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork - + " with code " + errorCode); - mPerNetworkListeners.remove(mNetwork); - } - - @Override - public void onDiscoveryStarted(String serviceType) { - // Wrapped listener was called upon registration, it is not called for discovery - // on each network - } - - @Override - public void onStopDiscoveryFailed(String serviceType, int errorCode) { - Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork - + " with code " + errorCode); - mPerNetworkListeners.remove(mNetwork); - if (mStopRequested && mPerNetworkListeners.size() == 0) { - // Do not report onStopDiscoveryFailed when some underlying listeners failed: - // this does not mean that all listeners did, and onStopDiscoveryFailed is not - // actionable anyway. Just report that discovery stopped. - mWrapped.onDiscoveryStopped(serviceType); - } - } - - @Override - public void onDiscoveryStopped(String serviceType) { - mPerNetworkListeners.remove(mNetwork); - if (mStopRequested && mPerNetworkListeners.size() == 0) { - mWrapped.onDiscoveryStopped(serviceType); - } - } - - @Override - public void onServiceFound(NsdServiceInfo serviceInfo) { - mFoundInfo.add(new TrackedNsdInfo(serviceInfo)); - mWrapped.onServiceFound(serviceInfo); - } - - @Override - public void onServiceLost(NsdServiceInfo serviceInfo) { - mFoundInfo.remove(new TrackedNsdInfo(serviceInfo)); - mWrapped.onServiceLost(serviceInfo); - } - } - } - - /** - * Create a new Nsd instance. Applications use - * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve - * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}. - * @param service the Binder interface - * @hide - hide this because it takes in a parameter of type INsdManager, which - * is a system private class. - */ - public NsdManager(Context context, INsdManager service) { - mContext = context; - - HandlerThread t = new HandlerThread("NsdManager"); - t.start(); - mHandler = new ServiceHandler(t.getLooper()); - - try { - mService = service.connect(new NsdCallbackImpl(mHandler)); - } catch (RemoteException e) { - throw new RuntimeException("Failed to connect to NsdService"); - } - - // Only proactively start the daemon if the target SDK < S, otherwise the internal service - // would automatically start/stop the native daemon as needed. - if (!CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) { - try { - mService.startDaemon(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to proactively start daemon"); - // Continue: the daemon can still be started on-demand later - } - } - } - - private static class NsdCallbackImpl extends INsdManagerCallback.Stub { - private final Handler mServHandler; - - NsdCallbackImpl(Handler serviceHandler) { - mServHandler = serviceHandler; - } - - private void sendInfo(int message, int listenerKey, NsdServiceInfo info) { - mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey, info)); - } - - private void sendError(int message, int listenerKey, int error) { - mServHandler.sendMessage(mServHandler.obtainMessage(message, error, listenerKey)); - } - - private void sendNoArg(int message, int listenerKey) { - mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey)); - } - - @Override - public void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) { - sendInfo(DISCOVER_SERVICES_STARTED, listenerKey, info); - } - - @Override - public void onDiscoverServicesFailed(int listenerKey, int error) { - sendError(DISCOVER_SERVICES_FAILED, listenerKey, error); - } - - @Override - public void onServiceFound(int listenerKey, NsdServiceInfo info) { - sendInfo(SERVICE_FOUND, listenerKey, info); - } - - @Override - public void onServiceLost(int listenerKey, NsdServiceInfo info) { - sendInfo(SERVICE_LOST, listenerKey, info); - } - - @Override - public void onStopDiscoveryFailed(int listenerKey, int error) { - sendError(STOP_DISCOVERY_FAILED, listenerKey, error); - } - - @Override - public void onStopDiscoverySucceeded(int listenerKey) { - sendNoArg(STOP_DISCOVERY_SUCCEEDED, listenerKey); - } - - @Override - public void onRegisterServiceFailed(int listenerKey, int error) { - sendError(REGISTER_SERVICE_FAILED, listenerKey, error); - } - - @Override - public void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) { - sendInfo(REGISTER_SERVICE_SUCCEEDED, listenerKey, info); - } - - @Override - public void onUnregisterServiceFailed(int listenerKey, int error) { - sendError(UNREGISTER_SERVICE_FAILED, listenerKey, error); - } - - @Override - public void onUnregisterServiceSucceeded(int listenerKey) { - sendNoArg(UNREGISTER_SERVICE_SUCCEEDED, listenerKey); - } - - @Override - public void onResolveServiceFailed(int listenerKey, int error) { - sendError(RESOLVE_SERVICE_FAILED, listenerKey, error); - } - - @Override - public void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) { - sendInfo(RESOLVE_SERVICE_SUCCEEDED, listenerKey, info); - } - } - - /** - * Failures are passed with {@link RegistrationListener#onRegistrationFailed}, - * {@link RegistrationListener#onUnregistrationFailed}, - * {@link DiscoveryListener#onStartDiscoveryFailed}, - * {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}. - * - * Indicates that the operation failed due to an internal error. - */ - public static final int FAILURE_INTERNAL_ERROR = 0; - - /** - * Indicates that the operation failed because it is already active. - */ - public static final int FAILURE_ALREADY_ACTIVE = 3; - - /** - * Indicates that the operation failed because the maximum outstanding - * requests from the applications have reached. - */ - public static final int FAILURE_MAX_LIMIT = 4; - - /** Interface for callback invocation for service discovery */ - public interface DiscoveryListener { - - public void onStartDiscoveryFailed(String serviceType, int errorCode); - - public void onStopDiscoveryFailed(String serviceType, int errorCode); - - public void onDiscoveryStarted(String serviceType); - - public void onDiscoveryStopped(String serviceType); - - public void onServiceFound(NsdServiceInfo serviceInfo); - - public void onServiceLost(NsdServiceInfo serviceInfo); - } - - /** Interface for callback invocation for service registration */ - public interface RegistrationListener { - - public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode); - - public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode); - - public void onServiceRegistered(NsdServiceInfo serviceInfo); - - public void onServiceUnregistered(NsdServiceInfo serviceInfo); - } - - /** Interface for callback invocation for service resolution */ - public interface ResolveListener { - - public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode); - - public void onServiceResolved(NsdServiceInfo serviceInfo); - } - - @VisibleForTesting - class ServiceHandler extends Handler { - ServiceHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message message) { - final int what = message.what; - final int key = message.arg2; - final Object listener; - final NsdServiceInfo ns; - final Executor executor; - synchronized (mMapLock) { - listener = mListenerMap.get(key); - ns = mServiceMap.get(key); - executor = mExecutorMap.get(key); - } - if (listener == null) { - Log.d(TAG, "Stale key " + message.arg2); - return; - } - if (DBG) { - Log.d(TAG, "received " + nameOf(what) + " for key " + key + ", service " + ns); - } - switch (what) { - case DISCOVER_SERVICES_STARTED: - final String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); - executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStarted(s)); - break; - case DISCOVER_SERVICES_FAILED: - removeListener(key); - executor.execute(() -> ((DiscoveryListener) listener).onStartDiscoveryFailed( - getNsdServiceInfoType(ns), message.arg1)); - break; - case SERVICE_FOUND: - executor.execute(() -> ((DiscoveryListener) listener).onServiceFound( - (NsdServiceInfo) message.obj)); - break; - case SERVICE_LOST: - executor.execute(() -> ((DiscoveryListener) listener).onServiceLost( - (NsdServiceInfo) message.obj)); - break; - case STOP_DISCOVERY_FAILED: - // TODO: failure to stop discovery should be internal and retried internally, as - // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED - removeListener(key); - executor.execute(() -> ((DiscoveryListener) listener).onStopDiscoveryFailed( - getNsdServiceInfoType(ns), message.arg1)); - break; - case STOP_DISCOVERY_SUCCEEDED: - removeListener(key); - executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStopped( - getNsdServiceInfoType(ns))); - break; - case REGISTER_SERVICE_FAILED: - removeListener(key); - executor.execute(() -> ((RegistrationListener) listener).onRegistrationFailed( - ns, message.arg1)); - break; - case REGISTER_SERVICE_SUCCEEDED: - executor.execute(() -> ((RegistrationListener) listener).onServiceRegistered( - (NsdServiceInfo) message.obj)); - break; - case UNREGISTER_SERVICE_FAILED: - removeListener(key); - executor.execute(() -> ((RegistrationListener) listener).onUnregistrationFailed( - ns, message.arg1)); - break; - case UNREGISTER_SERVICE_SUCCEEDED: - // TODO: do not unregister listener until service is unregistered, or provide - // alternative way for unregistering ? - removeListener(message.arg2); - executor.execute(() -> ((RegistrationListener) listener).onServiceUnregistered( - ns)); - break; - case RESOLVE_SERVICE_FAILED: - removeListener(key); - executor.execute(() -> ((ResolveListener) listener).onResolveFailed( - ns, message.arg1)); - break; - case RESOLVE_SERVICE_SUCCEEDED: - removeListener(key); - executor.execute(() -> ((ResolveListener) listener).onServiceResolved( - (NsdServiceInfo) message.obj)); - break; - default: - Log.d(TAG, "Ignored " + message); - break; - } - } - } - - private int nextListenerKey() { - // Ensure mListenerKey >= FIRST_LISTENER_KEY; - mListenerKey = Math.max(FIRST_LISTENER_KEY, mListenerKey + 1); - return mListenerKey; - } - - // Assert that the listener is not in the map, then add it and returns its key - private int putListener(Object listener, Executor e, NsdServiceInfo s) { - checkListener(listener); - final int key; - synchronized (mMapLock) { - int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - throw new IllegalArgumentException("listener already in use"); - } - key = nextListenerKey(); - mListenerMap.put(key, listener); - mServiceMap.put(key, s); - mExecutorMap.put(key, e); - } - return key; - } - - private void removeListener(int key) { - synchronized (mMapLock) { - mListenerMap.remove(key); - mServiceMap.remove(key); - mExecutorMap.remove(key); - } - } - - private int getListenerKey(Object listener) { - checkListener(listener); - synchronized (mMapLock) { - int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex == -1) { - throw new IllegalArgumentException("listener not registered"); - } - return mListenerMap.keyAt(valueIndex); - } - } - - private static String getNsdServiceInfoType(NsdServiceInfo s) { - if (s == null) return "?"; - return s.getServiceType(); - } - - /** - * Register a service to be discovered by other services. - * - * <p> The function call immediately returns after sending a request to register service - * to the framework. The application is notified of a successful registration - * through the callback {@link RegistrationListener#onServiceRegistered} or a failure - * through {@link RegistrationListener#onRegistrationFailed}. - * - * <p> The application should call {@link #unregisterService} when the service - * registration is no longer required, and/or whenever the application is stopped. - * - * @param serviceInfo The service being registered - * @param protocolType The service discovery protocol - * @param listener The listener notifies of a successful registration and is used to - * unregister this service through a call on {@link #unregisterService}. Cannot be null. - * Cannot be in use for an active service registration. - */ - public void registerService(NsdServiceInfo serviceInfo, int protocolType, - RegistrationListener listener) { - registerService(serviceInfo, protocolType, Runnable::run, listener); - } - - /** - * Register a service to be discovered by other services. - * - * <p> The function call immediately returns after sending a request to register service - * to the framework. The application is notified of a successful registration - * through the callback {@link RegistrationListener#onServiceRegistered} or a failure - * through {@link RegistrationListener#onRegistrationFailed}. - * - * <p> The application should call {@link #unregisterService} when the service - * registration is no longer required, and/or whenever the application is stopped. - * @param serviceInfo The service being registered - * @param protocolType The service discovery protocol - * @param executor Executor to run listener callbacks with - * @param listener The listener notifies of a successful registration and is used to - * unregister this service through a call on {@link #unregisterService}. Cannot be null. - */ - public void registerService(@NonNull NsdServiceInfo serviceInfo, int protocolType, - @NonNull Executor executor, @NonNull RegistrationListener listener) { - if (serviceInfo.getPort() <= 0) { - throw new IllegalArgumentException("Invalid port number"); - } - checkServiceInfo(serviceInfo); - checkProtocol(protocolType); - int key = putListener(listener, executor, serviceInfo); - try { - mService.registerService(key, serviceInfo); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Unregister a service registered through {@link #registerService}. A successful - * unregister is notified to the application with a call to - * {@link RegistrationListener#onServiceUnregistered}. - * - * @param listener This should be the listener object that was passed to - * {@link #registerService}. It identifies the service that should be unregistered - * and notifies of a successful or unsuccessful unregistration via the listener - * callbacks. In API versions 20 and above, the listener object may be used for - * another service registration once the callback has been called. In API versions <= 19, - * there is no entirely reliable way to know when a listener may be re-used, and a new - * listener should be created for each service registration request. - */ - public void unregisterService(RegistrationListener listener) { - int id = getListenerKey(listener); - try { - mService.unregisterService(id); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Initiate service discovery to browse for instances of a service type. Service discovery - * consumes network bandwidth and will continue until the application calls - * {@link #stopServiceDiscovery}. - * - * <p> The function call immediately returns after sending a request to start service - * discovery to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure - * through {@link DiscoveryListener#onStartDiscoveryFailed}. - * - * <p> Upon successful start, application is notified when a service is found with - * {@link DiscoveryListener#onServiceFound} or when a service is lost with - * {@link DiscoveryListener#onServiceLost}. - * - * <p> Upon failure to start, service discovery is not active and application does - * not need to invoke {@link #stopServiceDiscovery} - * - * <p> The application should call {@link #stopServiceDiscovery} when discovery of this - * service type is no longer required, and/or whenever the application is paused or - * stopped. - * - * @param serviceType The service type being discovered. Examples include "_http._tcp" for - * http services or "_ipp._tcp" for printers - * @param protocolType The service discovery protocol - * @param listener The listener notifies of a successful discovery and is used - * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - * Cannot be null. Cannot be in use for an active service discovery. - */ - public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - discoverServices(serviceType, protocolType, (Network) null, Runnable::run, listener); - } - - /** - * Initiate service discovery to browse for instances of a service type. Service discovery - * consumes network bandwidth and will continue until the application calls - * {@link #stopServiceDiscovery}. - * - * <p> The function call immediately returns after sending a request to start service - * discovery to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure - * through {@link DiscoveryListener#onStartDiscoveryFailed}. - * - * <p> Upon successful start, application is notified when a service is found with - * {@link DiscoveryListener#onServiceFound} or when a service is lost with - * {@link DiscoveryListener#onServiceLost}. - * - * <p> Upon failure to start, service discovery is not active and application does - * not need to invoke {@link #stopServiceDiscovery} - * - * <p> The application should call {@link #stopServiceDiscovery} when discovery of this - * service type is no longer required, and/or whenever the application is paused or - * stopped. - * @param serviceType The service type being discovered. Examples include "_http._tcp" for - * http services or "_ipp._tcp" for printers - * @param protocolType The service discovery protocol - * @param network Network to discover services on, or null to discover on all available networks - * @param executor Executor to run listener callbacks with - * @param listener The listener notifies of a successful discovery and is used - * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - */ - public void discoverServices(@NonNull String serviceType, int protocolType, - @Nullable Network network, @NonNull Executor executor, - @NonNull DiscoveryListener listener) { - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - checkProtocol(protocolType); - - NsdServiceInfo s = new NsdServiceInfo(); - s.setServiceType(serviceType); - s.setNetwork(network); - - int key = putListener(listener, executor, s); - try { - mService.discoverServices(key, s); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Initiate service discovery to browse for instances of a service type. Service discovery - * consumes network bandwidth and will continue until the application calls - * {@link #stopServiceDiscovery}. - * - * <p> The function call immediately returns after sending a request to start service - * discovery to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure - * through {@link DiscoveryListener#onStartDiscoveryFailed}. - * - * <p> Upon successful start, application is notified when a service is found with - * {@link DiscoveryListener#onServiceFound} or when a service is lost with - * {@link DiscoveryListener#onServiceLost}. - * - * <p> Upon failure to start, service discovery is not active and application does - * not need to invoke {@link #stopServiceDiscovery} - * - * <p> The application should call {@link #stopServiceDiscovery} when discovery of this - * service type is no longer required, and/or whenever the application is paused or - * stopped. - * - * <p> During discovery, new networks may connect or existing networks may disconnect - for - * example if wifi is reconnected. When a service was found on a network that disconnects, - * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that - * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called - * for services found on that network. Applications that do not want to track networks - * themselves are encouraged to use this method instead of other overloads of - * {@code discoverServices}, as they will receive proper notifications when a service becomes - * available or unavailable due to network changes. - * @param serviceType The service type being discovered. Examples include "_http._tcp" for - * http services or "_ipp._tcp" for printers - * @param protocolType The service discovery protocol - * @param networkRequest Request specifying networks that should be considered when discovering - * @param executor Executor to run listener callbacks with - * @param listener The listener notifies of a successful discovery and is used - * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void discoverServices(@NonNull String serviceType, int protocolType, - @NonNull NetworkRequest networkRequest, @NonNull Executor executor, - @NonNull DiscoveryListener listener) { - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null"); - checkProtocol(protocolType); - - NsdServiceInfo s = new NsdServiceInfo(); - s.setServiceType(serviceType); - - final int baseListenerKey = putListener(listener, executor, s); - - final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker( - serviceType, protocolType, executor, listener); - - synchronized (mPerNetworkDiscoveryMap) { - mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo); - discoveryInfo.start(networkRequest); - } - } - - /** - * Stop service discovery initiated with {@link #discoverServices}. An active service - * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} - * and it stays active until the application invokes a stop service discovery. A successful - * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}. - * - * <p> Upon failure to stop service discovery, application is notified through - * {@link DiscoveryListener#onStopDiscoveryFailed}. - * - * @param listener This should be the listener object that was passed to {@link #discoverServices}. - * It identifies the discovery that should be stopped and notifies of a successful or - * unsuccessful stop. In API versions 20 and above, the listener object may be used for - * another service discovery once the callback has been called. In API versions <= 19, - * there is no entirely reliable way to know when a listener may be re-used, and a new - * listener should be created for each service discovery request. - */ - public void stopServiceDiscovery(DiscoveryListener listener) { - int id = getListenerKey(listener); - // If this is a PerNetworkDiscovery request, handle it as such - synchronized (mPerNetworkDiscoveryMap) { - final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id); - if (info != null) { - info.requestStop(); - return; - } - } - try { - mService.stopDiscovery(id); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Resolve a discovered service. An application can resolve a service right before - * establishing a connection to fetch the IP and port details on which to setup - * the connection. - * - * @param serviceInfo service to be resolved - * @param listener to receive callback upon success or failure. Cannot be null. - * Cannot be in use for an active service resolution. - */ - public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { - resolveService(serviceInfo, Runnable::run, listener); - } - - /** - * Resolve a discovered service. An application can resolve a service right before - * establishing a connection to fetch the IP and port details on which to setup - * the connection. - * @param serviceInfo service to be resolved - * @param executor Executor to run listener callbacks with - * @param listener to receive callback upon success or failure. - */ - public void resolveService(@NonNull NsdServiceInfo serviceInfo, - @NonNull Executor executor, @NonNull ResolveListener listener) { - checkServiceInfo(serviceInfo); - int key = putListener(listener, executor, serviceInfo); - try { - mService.resolveService(key, serviceInfo); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - private static void checkListener(Object listener) { - Objects.requireNonNull(listener, "listener cannot be null"); - } - - private static void checkProtocol(int protocolType) { - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } - } - - private static void checkServiceInfo(NsdServiceInfo serviceInfo) { - Objects.requireNonNull(serviceInfo, "NsdServiceInfo cannot be null"); - if (TextUtils.isEmpty(serviceInfo.getServiceName())) { - throw new IllegalArgumentException("Service name cannot be empty"); - } - if (TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java deleted file mode 100644 index 8506db1fbe01..000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.net.nsd; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.Network; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Base64; -import android.util.Log; - -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Map; - -/** - * A class representing service information for network service discovery - * {@see NsdManager} - */ -public final class NsdServiceInfo implements Parcelable { - - private static final String TAG = "NsdServiceInfo"; - - private String mServiceName; - - private String mServiceType; - - private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<>(); - - private InetAddress mHost; - - private int mPort; - - @Nullable - private Network mNetwork; - - public NsdServiceInfo() { - } - - /** @hide */ - public NsdServiceInfo(String sn, String rt) { - mServiceName = sn; - mServiceType = rt; - } - - /** Get the service name */ - public String getServiceName() { - return mServiceName; - } - - /** Set the service name */ - public void setServiceName(String s) { - mServiceName = s; - } - - /** Get the service type */ - public String getServiceType() { - return mServiceType; - } - - /** Set the service type */ - public void setServiceType(String s) { - mServiceType = s; - } - - /** Get the host address. The host address is valid for a resolved service. */ - public InetAddress getHost() { - return mHost; - } - - /** Set the host address */ - public void setHost(InetAddress s) { - mHost = s; - } - - /** Get port number. The port number is valid for a resolved service. */ - public int getPort() { - return mPort; - } - - /** Set port number */ - public void setPort(int p) { - mPort = p; - } - - /** - * Unpack txt information from a base-64 encoded byte array. - * - * @param rawRecords The raw base64 encoded records string read from netd. - * - * @hide - */ - public void setTxtRecords(@NonNull String rawRecords) { - byte[] txtRecordsRawBytes = Base64.decode(rawRecords, Base64.DEFAULT); - - // There can be multiple TXT records after each other. Each record has to following format: - // - // byte type required meaning - // ------------------- ------------------- -------- ---------------------------------- - // 0 unsigned 8 bit yes size of record excluding this byte - // 1 - n ASCII but not '=' yes key - // n + 1 '=' optional separator of key and value - // n + 2 - record size uninterpreted bytes optional value - // - // Example legal records: - // [11, 'm', 'y', 'k', 'e', 'y', '=', 0x0, 0x4, 0x65, 0x7, 0xff] - // [17, 'm', 'y', 'K', 'e', 'y', 'W', 'i', 't', 'h', 'N', 'o', 'V', 'a', 'l', 'u', 'e', '='] - // [12, 'm', 'y', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'K', 'e', 'y'] - // - // Example corrupted records - // [3, =, 1, 2] <- key is empty - // [3, 0, =, 2] <- key contains non-ASCII character. We handle this by replacing the - // invalid characters instead of skipping the record. - // [30, 'a', =, 2] <- length exceeds total left over bytes in the TXT records array, we - // handle this by reducing the length of the record as needed. - int pos = 0; - while (pos < txtRecordsRawBytes.length) { - // recordLen is an unsigned 8 bit value - int recordLen = txtRecordsRawBytes[pos] & 0xff; - pos += 1; - - try { - if (recordLen == 0) { - throw new IllegalArgumentException("Zero sized txt record"); - } else if (pos + recordLen > txtRecordsRawBytes.length) { - Log.w(TAG, "Corrupt record length (pos = " + pos + "): " + recordLen); - recordLen = txtRecordsRawBytes.length - pos; - } - - // Decode key-value records - String key = null; - byte[] value = null; - int valueLen = 0; - for (int i = pos; i < pos + recordLen; i++) { - if (key == null) { - if (txtRecordsRawBytes[i] == '=') { - key = new String(txtRecordsRawBytes, pos, i - pos, - StandardCharsets.US_ASCII); - } - } else { - if (value == null) { - value = new byte[recordLen - key.length() - 1]; - } - value[valueLen] = txtRecordsRawBytes[i]; - valueLen++; - } - } - - // If '=' was not found we have a boolean record - if (key == null) { - key = new String(txtRecordsRawBytes, pos, recordLen, StandardCharsets.US_ASCII); - } - - if (TextUtils.isEmpty(key)) { - // Empty keys are not allowed (RFC6763 6.4) - throw new IllegalArgumentException("Invalid txt record (key is empty)"); - } - - if (getAttributes().containsKey(key)) { - // When we have a duplicate record, the later ones are ignored (RFC6763 6.4) - throw new IllegalArgumentException("Invalid txt record (duplicate key \"" + key + "\")"); - } - - setAttribute(key, value); - } catch (IllegalArgumentException e) { - Log.e(TAG, "While parsing txt records (pos = " + pos + "): " + e.getMessage()); - } - - pos += recordLen; - } - } - - /** @hide */ - @UnsupportedAppUsage - public void setAttribute(String key, byte[] value) { - if (TextUtils.isEmpty(key)) { - throw new IllegalArgumentException("Key cannot be empty"); - } - - // Key must be printable US-ASCII, excluding =. - for (int i = 0; i < key.length(); ++i) { - char character = key.charAt(i); - if (character < 0x20 || character > 0x7E) { - throw new IllegalArgumentException("Key strings must be printable US-ASCII"); - } else if (character == 0x3D) { - throw new IllegalArgumentException("Key strings must not include '='"); - } - } - - // Key length + value length must be < 255. - if (key.length() + (value == null ? 0 : value.length) >= 255) { - throw new IllegalArgumentException("Key length + value length must be < 255 bytes"); - } - - // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4. - if (key.length() > 9) { - Log.w(TAG, "Key lengths > 9 are discouraged: " + key); - } - - // Check against total TXT record size limits. - // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2. - int txtRecordSize = getTxtRecordSize(); - int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2; - if (futureSize > 1300) { - throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes"); - } else if (futureSize > 400) { - Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur"); - } - - mTxtRecord.put(key, value); - } - - /** - * Add a service attribute as a key/value pair. - * - * <p> Service attributes are included as DNS-SD TXT record pairs. - * - * <p> The key must be US-ASCII printable characters, excluding the '=' character. Values may - * be UTF-8 strings or null. The total length of key + value must be less than 255 bytes. - * - * <p> Keys should be short, ideally no more than 9 characters, and unique per instance of - * {@link NsdServiceInfo}. Calling {@link #setAttribute} twice with the same key will overwrite - * first value. - */ - public void setAttribute(String key, String value) { - try { - setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException("Value must be UTF-8"); - } - } - - /** Remove an attribute by key */ - public void removeAttribute(String key) { - mTxtRecord.remove(key); - } - - /** - * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only - * valid for a resolved service. - * - * <p> The returned map is unmodifiable; changes must be made through {@link #setAttribute} and - * {@link #removeAttribute}. - */ - public Map<String, byte[]> getAttributes() { - return Collections.unmodifiableMap(mTxtRecord); - } - - private int getTxtRecordSize() { - int txtRecordSize = 0; - for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) { - txtRecordSize += 2; // One for the length byte, one for the = between key and value. - txtRecordSize += entry.getKey().length(); - byte[] value = entry.getValue(); - txtRecordSize += value == null ? 0 : value.length; - } - return txtRecordSize; - } - - /** @hide */ - public @NonNull byte[] getTxtRecord() { - int txtRecordSize = getTxtRecordSize(); - if (txtRecordSize == 0) { - return new byte[]{}; - } - - byte[] txtRecord = new byte[txtRecordSize]; - int ptr = 0; - for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) { - String key = entry.getKey(); - byte[] value = entry.getValue(); - - // One byte to record the length of this key/value pair. - txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1); - - // The key, in US-ASCII. - // Note: use the StandardCharsets const here because it doesn't raise exceptions and we - // already know the key is ASCII at this point. - System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr, - key.length()); - ptr += key.length(); - - // US-ASCII '=' character. - txtRecord[ptr++] = (byte)'='; - - // The value, as any raw bytes. - if (value != null) { - System.arraycopy(value, 0, txtRecord, ptr, value.length); - ptr += value.length; - } - } - return txtRecord; - } - - /** - * Get the network where the service can be found. - * - * This is never null if this {@link NsdServiceInfo} was obtained from - * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}. - */ - @Nullable - public Network getNetwork() { - return mNetwork; - } - - /** - * Set the network where the service can be found. - * @param network The network, or null to search for, or to announce, the service on all - * connected networks. - */ - public void setNetwork(@Nullable Network network) { - mNetwork = network; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("name: ").append(mServiceName) - .append(", type: ").append(mServiceType) - .append(", host: ").append(mHost) - .append(", port: ").append(mPort) - .append(", network: ").append(mNetwork); - - byte[] txtRecord = getTxtRecord(); - sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8)); - return sb.toString(); - } - - /** Implement the Parcelable interface */ - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mServiceName); - dest.writeString(mServiceType); - if (mHost != null) { - dest.writeInt(1); - dest.writeByteArray(mHost.getAddress()); - } else { - dest.writeInt(0); - } - dest.writeInt(mPort); - - // TXT record key/value pairs. - dest.writeInt(mTxtRecord.size()); - for (String key : mTxtRecord.keySet()) { - byte[] value = mTxtRecord.get(key); - if (value != null) { - dest.writeInt(1); - dest.writeInt(value.length); - dest.writeByteArray(value); - } else { - dest.writeInt(0); - } - dest.writeString(key); - } - - dest.writeParcelable(mNetwork, 0); - } - - /** Implement the Parcelable interface */ - public static final @android.annotation.NonNull Creator<NsdServiceInfo> CREATOR = - new Creator<NsdServiceInfo>() { - public NsdServiceInfo createFromParcel(Parcel in) { - NsdServiceInfo info = new NsdServiceInfo(); - info.mServiceName = in.readString(); - info.mServiceType = in.readString(); - - if (in.readInt() == 1) { - try { - info.mHost = InetAddress.getByAddress(in.createByteArray()); - } catch (java.net.UnknownHostException e) {} - } - - info.mPort = in.readInt(); - - // TXT record key/value pairs. - int recordCount = in.readInt(); - for (int i = 0; i < recordCount; ++i) { - byte[] valueArray = null; - if (in.readInt() == 1) { - int valueLength = in.readInt(); - valueArray = new byte[valueLength]; - in.readByteArray(valueArray); - } - info.mTxtRecord.put(in.readString(), valueArray); - } - info.mNetwork = in.readParcelable(null, Network.class); - return info; - } - - public NsdServiceInfo[] newArray(int size) { - return new NsdServiceInfo[size]; - } - }; -} diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp deleted file mode 100644 index 4b799c599be9..000000000000 --- a/packages/ConnectivityT/service/Android.bp +++ /dev/null @@ -1,156 +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 { - // See: http://go/android-license-faq - default_applicable_licenses: ["Android-Apache-2.0"], -} - -// NetworkStats related libraries. - -filegroup { - name: "services.connectivity-netstats-sources", - srcs: [ - "src/com/android/server/net/NetworkIdentity*.java", - "src/com/android/server/net/NetworkStats*.java", - "src/com/android/server/net/BpfInterfaceMapUpdater.java", - "src/com/android/server/net/InterfaceMapValue.java", - "src/com/android/server/net/CookieTagMapKey.java", - "src/com/android/server/net/CookieTagMapValue.java", - "src/com/android/server/net/StatsMapKey.java", - "src/com/android/server/net/StatsMapValue.java", - "src/com/android/server/net/UidStatsMapKey.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// For test code only. -filegroup { - name: "lib_networkStatsFactory_native", - srcs: [ - "jni/com_android_server_net_NetworkStatsFactory.cpp", - ], - path: "jni", - visibility: [ - "//packages/modules/Connectivity:__subpackages__", - ], -} - -filegroup { - name: "services.connectivity-netstats-jni-sources", - srcs: [ - "jni/com_android_server_net_NetworkStatsFactory.cpp", - "jni/com_android_server_net_NetworkStatsService.cpp", - ], - path: "jni", - visibility: [ - "//packages/modules/Connectivity:__subpackages__", - ], -} - -// Nsd related libraries. - -filegroup { - name: "services.connectivity-nsd-sources", - srcs: [ - "src/com/android/server/INativeDaemon*.java", - "src/com/android/server/NativeDaemon*.java", - "src/com/android/server/Nsd*.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// IpSec related libraries. - -filegroup { - name: "services.connectivity-ipsec-sources", - srcs: [ - "src/com/android/server/IpSecService.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// Ethernet related libraries. - -filegroup { - name: "services.connectivity-ethernet-sources", - srcs: [ - "src/com/android/server/net/DelayedDiskWrite.java", - "src/com/android/server/net/IpConfigStore.java", - ], - path: "src", - visibility: [ - "//frameworks/opt/net/ethernet/tests", - ], -} - -// Connectivity-T common libraries. - -// TODO: remove this empty filegroup. -filegroup { - name: "services.connectivity-tiramisu-sources", - srcs: [], - path: "src", - visibility: ["//frameworks/base/services/core"], -} - -filegroup { - name: "services.connectivity-tiramisu-updatable-sources", - srcs: [ - ":services.connectivity-ethernet-sources", - ":services.connectivity-ipsec-sources", - ":services.connectivity-netstats-sources", - ":services.connectivity-nsd-sources", - ], - path: "src", - visibility: [ - "//packages/modules/Connectivity:__subpackages__", - ], -} - -cc_library_shared { - name: "libcom_android_net_module_util_jni", - min_sdk_version: "30", - cflags: [ - "-Wall", - "-Werror", - "-Wno-unused-parameter", - "-Wthread-safety", - ], - srcs: [ - "jni/onload.cpp", - ], - stl: "libc++_static", - static_libs: [ - "libnet_utils_device_common_bpfjni", - ], - shared_libs: [ - "liblog", - "libnativehelper", - ], - apex_available: [ - "//apex_available:platform", - ], -} diff --git a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp deleted file mode 100644 index 8b6526ff49f0..000000000000 --- a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "NetworkStats" - -#include <errno.h> -#include <inttypes.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <vector> - -#include <jni.h> - -#include <nativehelper/JNIHelp.h> -#include <nativehelper/ScopedUtfChars.h> -#include <nativehelper/ScopedLocalRef.h> -#include <nativehelper/ScopedPrimitiveArray.h> - -#include <utils/Log.h> -#include <utils/misc.h> - -#include "android-base/unique_fd.h" -#include "bpf/BpfUtils.h" -#include "netdbpf/BpfNetworkStats.h" - -using android::bpf::parseBpfNetworkStatsDetail; -using android::bpf::stats_line; - -namespace android { - -static jclass gStringClass; - -static struct { - jfieldID size; - jfieldID capacity; - jfieldID iface; - jfieldID uid; - jfieldID set; - jfieldID tag; - jfieldID metered; - jfieldID roaming; - jfieldID defaultNetwork; - jfieldID rxBytes; - jfieldID rxPackets; - jfieldID txBytes; - jfieldID txPackets; - jfieldID operations; -} gNetworkStatsClassInfo; - -static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) -{ - if (!grow) { - jobjectArray array = (jobjectArray)env->GetObjectField(obj, field); - if (array != NULL) { - return array; - } - } - return env->NewObjectArray(size, gStringClass, NULL); -} - -static jintArray get_int_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) -{ - if (!grow) { - jintArray array = (jintArray)env->GetObjectField(obj, field); - if (array != NULL) { - return array; - } - } - return env->NewIntArray(size); -} - -static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) -{ - if (!grow) { - jlongArray array = (jlongArray)env->GetObjectField(obj, field); - if (array != NULL) { - return array; - } - } - return env->NewLongArray(size); -} - -static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines, - const std::vector<std::string>& limitIfaces, - int limitTag, int limitUid, const char* path) { - FILE* fp = fopen(path, "re"); - if (fp == NULL) { - return -1; - } - - int lastIdx = 1; - int idx; - char buffer[384]; - while (fgets(buffer, sizeof(buffer), fp) != NULL) { - stats_line s; - int64_t rawTag; - char* pos = buffer; - char* endPos; - // First field is the index. - idx = (int)strtol(pos, &endPos, 10); - //ALOGI("Index #%d: %s", idx, buffer); - if (pos == endPos) { - // Skip lines that don't start with in index. In particular, - // this will skip the initial header line. - continue; - } - if (idx != lastIdx + 1) { - ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer); - fclose(fp); - return -1; - } - lastIdx = idx; - pos = endPos; - // Skip whitespace. - while (*pos == ' ') { - pos++; - } - // Next field is iface. - int ifaceIdx = 0; - while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) { - s.iface[ifaceIdx] = *pos; - ifaceIdx++; - pos++; - } - if (*pos != ' ') { - ALOGE("bad iface: %s", buffer); - fclose(fp); - return -1; - } - s.iface[ifaceIdx] = 0; - if (limitIfaces.size() > 0) { - // Is this an iface the caller is interested in? - int i = 0; - while (i < (int)limitIfaces.size()) { - if (limitIfaces[i] == s.iface) { - break; - } - i++; - } - if (i >= (int)limitIfaces.size()) { - // Nothing matched; skip this line. - //ALOGI("skipping due to iface: %s", buffer); - continue; - } - } - - // Ignore whitespace - while (*pos == ' ') pos++; - - // Find end of tag field - endPos = pos; - while (*endPos != ' ') endPos++; - - // Three digit field is always 0x0, otherwise parse - if (endPos - pos == 3) { - rawTag = 0; - } else { - if (sscanf(pos, "%" PRIx64, &rawTag) != 1) { - ALOGE("bad tag: %s", pos); - fclose(fp); - return -1; - } - } - s.tag = rawTag >> 32; - if (limitTag != -1 && s.tag != static_cast<uint32_t>(limitTag)) { - //ALOGI("skipping due to tag: %s", buffer); - continue; - } - pos = endPos; - - // Ignore whitespace - while (*pos == ' ') pos++; - - // Parse remaining fields. - if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, - &s.uid, &s.set, &s.rxBytes, &s.rxPackets, - &s.txBytes, &s.txPackets) == 6) { - if (limitUid != -1 && static_cast<uint32_t>(limitUid) != s.uid) { - //ALOGI("skipping due to uid: %s", buffer); - continue; - } - lines->push_back(s); - } else { - //ALOGI("skipping due to bad remaining fields: %s", pos); - } - } - - if (fclose(fp) != 0) { - ALOGE("Failed to close netstats file"); - return -1; - } - return 0; -} - -static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats, - std::vector<stats_line>& lines) { - int size = lines.size(); - - bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); - - ScopedLocalRef<jobjectArray> iface(env, get_string_array(env, stats, - gNetworkStatsClassInfo.iface, size, grow)); - if (iface.get() == NULL) return -1; - ScopedIntArrayRW uid(env, get_int_array(env, stats, - gNetworkStatsClassInfo.uid, size, grow)); - if (uid.get() == NULL) return -1; - ScopedIntArrayRW set(env, get_int_array(env, stats, - gNetworkStatsClassInfo.set, size, grow)); - if (set.get() == NULL) return -1; - ScopedIntArrayRW tag(env, get_int_array(env, stats, - gNetworkStatsClassInfo.tag, size, grow)); - if (tag.get() == NULL) return -1; - ScopedIntArrayRW metered(env, get_int_array(env, stats, - gNetworkStatsClassInfo.metered, size, grow)); - if (metered.get() == NULL) return -1; - ScopedIntArrayRW roaming(env, get_int_array(env, stats, - gNetworkStatsClassInfo.roaming, size, grow)); - if (roaming.get() == NULL) return -1; - ScopedIntArrayRW defaultNetwork(env, get_int_array(env, stats, - gNetworkStatsClassInfo.defaultNetwork, size, grow)); - if (defaultNetwork.get() == NULL) return -1; - ScopedLongArrayRW rxBytes(env, get_long_array(env, stats, - gNetworkStatsClassInfo.rxBytes, size, grow)); - if (rxBytes.get() == NULL) return -1; - ScopedLongArrayRW rxPackets(env, get_long_array(env, stats, - gNetworkStatsClassInfo.rxPackets, size, grow)); - if (rxPackets.get() == NULL) return -1; - ScopedLongArrayRW txBytes(env, get_long_array(env, stats, - gNetworkStatsClassInfo.txBytes, size, grow)); - if (txBytes.get() == NULL) return -1; - ScopedLongArrayRW txPackets(env, get_long_array(env, stats, - gNetworkStatsClassInfo.txPackets, size, grow)); - if (txPackets.get() == NULL) return -1; - ScopedLongArrayRW operations(env, get_long_array(env, stats, - gNetworkStatsClassInfo.operations, size, grow)); - if (operations.get() == NULL) return -1; - - for (int i = 0; i < size; i++) { - ScopedLocalRef<jstring> ifaceString(env, env->NewStringUTF(lines[i].iface)); - env->SetObjectArrayElement(iface.get(), i, ifaceString.get()); - - uid[i] = lines[i].uid; - set[i] = lines[i].set; - tag[i] = lines[i].tag; - // Metered, roaming and defaultNetwork are populated in Java-land. - rxBytes[i] = lines[i].rxBytes; - rxPackets[i] = lines[i].rxPackets; - txBytes[i] = lines[i].txBytes; - txPackets[i] = lines[i].txPackets; - } - - env->SetIntField(stats, gNetworkStatsClassInfo.size, size); - if (grow) { - env->SetIntField(stats, gNetworkStatsClassInfo.capacity, size); - env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get()); - env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.defaultNetwork, - defaultNetwork.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); - } - return 0; -} - -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, - jint limitUid, jobjectArray limitIfacesObj, jint limitTag, - jboolean useBpfStats) { - - std::vector<std::string> limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - for (int i = 0; i < num; i++) { - jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.push_back(std::string(string8.c_str())); - } - } - } - std::vector<stats_line> lines; - - - if (useBpfStats) { - if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) - return -1; - } else { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str()); - return -1; - } - if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, - limitUid, path8.c_str()) < 0) - return -1; - } - - return statsLinesToNetworkStats(env, clazz, stats, lines); -} - -static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) { - std::vector<stats_line> lines; - - if (parseBpfNetworkStatsDev(&lines) < 0) - return -1; - - return statsLinesToNetworkStats(env, clazz, stats, lines); -} - -static const JNINativeMethod gMethods[] = { - { "nativeReadNetworkStatsDetail", - "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I", - (void*) readNetworkStatsDetail }, - { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I", - (void*) readNetworkStatsDev }, -}; - -int register_android_server_net_NetworkStatsFactory(JNIEnv* env) { - int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods, - NELEM(gMethods)); - gStringClass = env->FindClass("java/lang/String"); - gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass)); - - jclass clazz = env->FindClass("android/net/NetworkStats"); - gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); - gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I"); - gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); - gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); - gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); - gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I"); - gNetworkStatsClassInfo.metered = env->GetFieldID(clazz, "metered", "[I"); - gNetworkStatsClassInfo.roaming = env->GetFieldID(clazz, "roaming", "[I"); - gNetworkStatsClassInfo.defaultNetwork = env->GetFieldID(clazz, "defaultNetwork", "[I"); - gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J"); - gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J"); - gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J"); - gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J"); - gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J"); - - return err; -} - -} diff --git a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp deleted file mode 100644 index 39cbaf716fc0..000000000000 --- a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "NetworkStatsNative" - -#include <cutils/qtaguid.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <jni.h> -#include <nativehelper/ScopedUtfChars.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <utils/Log.h> -#include <utils/misc.h> - -#include "bpf/BpfUtils.h" -#include "netdbpf/BpfNetworkStats.h" - -using android::bpf::bpfGetUidStats; -using android::bpf::bpfGetIfaceStats; - -namespace android { - -// NOTE: keep these in sync with TrafficStats.java -static const uint64_t UNKNOWN = -1; - -enum StatsType { - RX_BYTES = 0, - RX_PACKETS = 1, - TX_BYTES = 2, - TX_PACKETS = 3, - TCP_RX_PACKETS = 4, - TCP_TX_PACKETS = 5 -}; - -static uint64_t getStatsType(Stats* stats, StatsType type) { - switch (type) { - case RX_BYTES: - return stats->rxBytes; - case RX_PACKETS: - return stats->rxPackets; - case TX_BYTES: - return stats->txBytes; - case TX_PACKETS: - return stats->txPackets; - case TCP_RX_PACKETS: - return stats->tcpRxPackets; - case TCP_TX_PACKETS: - return stats->tcpTxPackets; - default: - return UNKNOWN; - } -} - -static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { - Stats stats = {}; - - if (bpfGetIfaceStats(NULL, &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } -} - -static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { - ScopedUtfChars iface8(env, iface); - if (iface8.c_str() == NULL) { - return UNKNOWN; - } - - Stats stats = {}; - - if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } -} - -static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { - Stats stats = {}; - - if (bpfGetUidStats(uid, &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } -} - -static const JNINativeMethod gMethods[] = { - {"nativeGetTotalStat", "(I)J", (void*)getTotalStat}, - {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat}, - {"nativeGetUidStat", "(II)J", (void*)getUidStat}, -}; - -int register_android_server_net_NetworkStatsService(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods, - NELEM(gMethods)); -} - -} diff --git a/packages/ConnectivityT/service/jni/onload.cpp b/packages/ConnectivityT/service/jni/onload.cpp deleted file mode 100644 index bca469756095..000000000000 --- a/packages/ConnectivityT/service/jni/onload.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <nativehelper/JNIHelp.h> -#include <log/log.h> - -namespace android { - -int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name); - -extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { - JNIEnv *env; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - ALOGE("GetEnv failed"); - return JNI_ERR; - } - - if (register_com_android_net_module_util_BpfMap(env, - "com/android/net/module/util/BpfMap") < 0) return JNI_ERR; - - return JNI_VERSION_1_6; -} - -}; - diff --git a/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java b/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java deleted file mode 100644 index 0cf9dcde012d..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -interface INativeDaemonConnectorCallbacks { - - void onDaemonConnected(); - boolean onCheckHoldWakeLock(int code); - boolean onEvent(int code, String raw, String[] cooked); -} diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java deleted file mode 100644 index 4bc40eae4404..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java +++ /dev/null @@ -1,1878 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import static android.Manifest.permission.DUMP; -import static android.net.IpSecManager.INVALID_RESOURCE_ID; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.AF_UNSPEC; -import static android.system.OsConstants.EINVAL; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.SOCK_DGRAM; - -import android.annotation.NonNull; -import android.app.AppOpsManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.IIpSecService; -import android.net.INetd; -import android.net.InetAddresses; -import android.net.IpSecAlgorithm; -import android.net.IpSecConfig; -import android.net.IpSecManager; -import android.net.IpSecSpiResponse; -import android.net.IpSecTransform; -import android.net.IpSecTransformResponse; -import android.net.IpSecTunnelInterfaceResponse; -import android.net.IpSecUdpEncapResponse; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.Network; -import android.net.TrafficStats; -import android.os.Binder; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.text.TextUtils; -import android.util.Log; -import android.util.Range; -import android.util.SparseArray; -import android.util.SparseBooleanArray; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; -import com.android.net.module.util.BinderUtils; -import com.android.net.module.util.NetdUtils; -import com.android.net.module.util.PermissionUtils; - -import libcore.io.IoUtils; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * A service to manage multiple clients that want to access the IpSec API. The service is - * responsible for maintaining a list of clients and managing the resources (and related quotas) - * that each of them own. - * - * <p>Synchronization in IpSecService is done on all entrypoints due to potential race conditions at - * the kernel/xfrm level. Further, this allows the simplifying assumption to be made that only one - * thread is ever running at a time. - * - * @hide - */ -public class IpSecService extends IIpSecService.Stub { - private static final String TAG = "IpSecService"; - private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - private static final int[] ADDRESS_FAMILIES = - new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; - - private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms - private static final InetAddress INADDR_ANY; - - @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; - - private final INetd mNetd; - - static { - try { - INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - } - - static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved - static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer - - /* Binder context for this service */ - private final Context mContext; - private final Dependencies mDeps; - - /** - * The next non-repeating global ID for tracking resources between users, this service, and - * kernel data structures. Accessing this variable is not thread safe, so it is only read or - * modified within blocks synchronized on IpSecService.this. We want to avoid -1 - * (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). - */ - @GuardedBy("IpSecService.this") - private int mNextResourceId = 1; - - /** - * Dependencies of IpSecService, for injection in tests. - */ - @VisibleForTesting - public static class Dependencies { - /** - * Get a reference to INetd. - */ - public INetd getNetdInstance(Context context) throws RemoteException { - final INetd netd = INetd.Stub.asInterface((IBinder) - context.getSystemService(Context.NETD_SERVICE)); - if (netd == null) { - throw new RemoteException("Failed to Get Netd Instance"); - } - return netd; - } - } - - final UidFdTagger mUidFdTagger; - - /** - * Interface for user-reference and kernel-resource cleanup. - * - * <p>This interface must be implemented for a resource to be reference counted. - */ - @VisibleForTesting - public interface IResource { - /** - * Invalidates a IResource object, ensuring it is invalid for the purposes of allocating new - * objects dependent on it. - * - * <p>Implementations of this method are expected to remove references to the IResource - * object from the IpSecService's tracking arrays. The removal from the arrays ensures that - * the resource is considered invalid for user access or allocation or use in other - * resources. - * - * <p>References to the IResource object may be held by other RefcountedResource objects, - * and as such, the underlying resources and quota may not be cleaned up. - */ - void invalidate() throws RemoteException; - - /** - * Releases underlying resources and related quotas. - * - * <p>Implementations of this method are expected to remove all system resources that are - * tracked by the IResource object. Due to other RefcountedResource objects potentially - * having references to the IResource object, freeUnderlyingResources may not always be - * called from releaseIfUnreferencedRecursively(). - */ - void freeUnderlyingResources() throws RemoteException; - } - - /** - * RefcountedResource manages references and dependencies in an exclusively acyclic graph. - * - * <p>RefcountedResource implements both explicit and implicit resource management. Creating a - * RefcountedResource object creates an explicit reference that must be freed by calling - * userRelease(). Additionally, adding this object as a child of another RefcountedResource - * object will add an implicit reference. - * - * <p>Resources are cleaned up when all references, both implicit and explicit, are released - * (ie, when userRelease() is called and when all parents have called releaseReference() on this - * object.) - */ - @VisibleForTesting - public class RefcountedResource<T extends IResource> implements IBinder.DeathRecipient { - private final T mResource; - private final List<RefcountedResource> mChildren; - int mRefCount = 1; // starts at 1 for user's reference. - IBinder mBinder; - - RefcountedResource(T resource, IBinder binder, RefcountedResource... children) { - synchronized (IpSecService.this) { - this.mResource = resource; - this.mChildren = new ArrayList<>(children.length); - this.mBinder = binder; - - for (RefcountedResource child : children) { - mChildren.add(child); - child.mRefCount++; - } - - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - e.rethrowFromSystemServer(); - } - } - } - - /** - * If the Binder object dies, this function is called to free the system resources that are - * being tracked by this record and to subsequently release this record for garbage - * collection - */ - @Override - public void binderDied() { - synchronized (IpSecService.this) { - try { - userRelease(); - } catch (Exception e) { - Log.e(TAG, "Failed to release resource: " + e); - } - } - } - - public T getResource() { - return mResource; - } - - /** - * Unlinks from binder and performs IpSecService resource cleanup (removes from resource - * arrays) - * - * <p>If this method has been previously called, the RefcountedResource's binder field will - * be null, and the method will return without performing the cleanup a second time. - * - * <p>Note that calling this function does not imply that kernel resources will be freed at - * this time, or that the related quota will be returned. Such actions will only be - * performed upon the reference count reaching zero. - */ - @GuardedBy("IpSecService.this") - public void userRelease() throws RemoteException { - // Prevent users from putting reference counts into a bad state by calling - // userRelease() multiple times. - if (mBinder == null) { - return; - } - - mBinder.unlinkToDeath(this, 0); - mBinder = null; - - mResource.invalidate(); - - releaseReference(); - } - - /** - * Removes a reference to this resource. If the resultant reference count is zero, the - * underlying resources are freed, and references to all child resources are also dropped - * recursively (resulting in them freeing their resources and children, etcetera) - * - * <p>This method also sets the reference count to an invalid value (-1) to signify that it - * has been fully released. Any subsequent calls to this method will result in an - * IllegalStateException being thrown due to resource already having been previously - * released - */ - @VisibleForTesting - @GuardedBy("IpSecService.this") - public void releaseReference() throws RemoteException { - mRefCount--; - - if (mRefCount > 0) { - return; - } else if (mRefCount < 0) { - throw new IllegalStateException( - "Invalid operation - resource has already been released."); - } - - // Cleanup own resources - mResource.freeUnderlyingResources(); - - // Cleanup child resources as needed - for (RefcountedResource<? extends IResource> child : mChildren) { - child.releaseReference(); - } - - // Enforce that resource cleanup can only be called once - // By decrementing the refcount (from 0 to -1), the next call will throw an - // IllegalStateException - it has already been released fully. - mRefCount--; - } - - @Override - public String toString() { - return new StringBuilder() - .append("{mResource=") - .append(mResource) - .append(", mRefCount=") - .append(mRefCount) - .append(", mChildren=") - .append(mChildren) - .append("}") - .toString(); - } - } - - /** - * Very simple counting class that looks much like a counting semaphore - * - * <p>This class is not thread-safe, and expects that that users of this class will ensure - * synchronization and thread safety by holding the IpSecService.this instance lock. - */ - @VisibleForTesting - static class ResourceTracker { - private final int mMax; - int mCurrent; - - ResourceTracker(int max) { - mMax = max; - mCurrent = 0; - } - - boolean isAvailable() { - return (mCurrent < mMax); - } - - void take() { - if (!isAvailable()) { - Log.wtf(TAG, "Too many resources allocated!"); - } - mCurrent++; - } - - void give() { - if (mCurrent <= 0) { - Log.wtf(TAG, "We've released this resource too many times"); - } - mCurrent--; - } - - @Override - public String toString() { - return new StringBuilder() - .append("{mCurrent=") - .append(mCurrent) - .append(", mMax=") - .append(mMax) - .append("}") - .toString(); - } - } - - @VisibleForTesting - static final class UserRecord { - /* Maximum number of each type of resource that a single UID may possess */ - - // Up to 4 active VPNs/IWLAN with potential soft handover. - public static final int MAX_NUM_TUNNEL_INTERFACES = 8; - public static final int MAX_NUM_ENCAP_SOCKETS = 16; - - // SPIs and Transforms are both cheap, and are 1:1 correlated. - public static final int MAX_NUM_TRANSFORMS = 64; - public static final int MAX_NUM_SPIS = 64; - - /** - * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing - * and explicit (user) reference management. - * - * <p>These are stored in separate arrays to improve debuggability and dump output clarity. - * - * <p>Resources are removed from this array when the user releases their explicit reference - * by calling one of the releaseResource() methods. - */ - final RefcountedResourceArray<SpiRecord> mSpiRecords = - new RefcountedResourceArray<>(SpiRecord.class.getSimpleName()); - final RefcountedResourceArray<TransformRecord> mTransformRecords = - new RefcountedResourceArray<>(TransformRecord.class.getSimpleName()); - final RefcountedResourceArray<EncapSocketRecord> mEncapSocketRecords = - new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName()); - final RefcountedResourceArray<TunnelInterfaceRecord> mTunnelInterfaceRecords = - new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName()); - - /** - * Trackers for quotas for each of the OwnedResource types. - * - * <p>These trackers are separate from the resource arrays, since they are incremented and - * decremented at different points in time. Specifically, quota is only returned upon final - * resource deallocation (after all explicit and implicit references are released). Note - * that it is possible that calls to releaseResource() will not return the used quota if - * there are other resources that depend on (are parents of) the resource being released. - */ - final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); - final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); - final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); - final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES); - - void removeSpiRecord(int resourceId) { - mSpiRecords.remove(resourceId); - } - - void removeTransformRecord(int resourceId) { - mTransformRecords.remove(resourceId); - } - - void removeTunnelInterfaceRecord(int resourceId) { - mTunnelInterfaceRecords.remove(resourceId); - } - - void removeEncapSocketRecord(int resourceId) { - mEncapSocketRecords.remove(resourceId); - } - - @Override - public String toString() { - return new StringBuilder() - .append("{mSpiQuotaTracker=") - .append(mSpiQuotaTracker) - .append(", mTransformQuotaTracker=") - .append(mTransformQuotaTracker) - .append(", mSocketQuotaTracker=") - .append(mSocketQuotaTracker) - .append(", mTunnelQuotaTracker=") - .append(mTunnelQuotaTracker) - .append(", mSpiRecords=") - .append(mSpiRecords) - .append(", mTransformRecords=") - .append(mTransformRecords) - .append(", mEncapSocketRecords=") - .append(mEncapSocketRecords) - .append(", mTunnelInterfaceRecords=") - .append(mTunnelInterfaceRecords) - .append("}") - .toString(); - } - } - - /** - * This class is not thread-safe, and expects that that users of this class will ensure - * synchronization and thread safety by holding the IpSecService.this instance lock. - */ - @VisibleForTesting - static final class UserResourceTracker { - private final SparseArray<UserRecord> mUserRecords = new SparseArray<>(); - - /** Lazy-initialization/getter that populates or retrieves the UserRecord as needed */ - public UserRecord getUserRecord(int uid) { - checkCallerUid(uid); - - UserRecord r = mUserRecords.get(uid); - if (r == null) { - r = new UserRecord(); - mUserRecords.put(uid, r); - } - return r; - } - - /** Safety method; guards against access of other user's UserRecords */ - private void checkCallerUid(int uid) { - if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) { - throw new SecurityException("Attempted access of unowned resources"); - } - } - - @Override - public String toString() { - return mUserRecords.toString(); - } - } - - @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker(); - - /** - * The OwnedResourceRecord class provides a facility to cleanly and reliably track system - * resources. It relies on a provided resourceId that should uniquely identify the kernel - * resource. To use this class, the user should implement the invalidate() and - * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource - * tracking arrays and kernel resources, respectively. - * - * <p>This class associates kernel resources with the UID that owns and controls them. - */ - private abstract class OwnedResourceRecord implements IResource { - final int mPid; - final int mUid; - protected final int mResourceId; - - OwnedResourceRecord(int resourceId) { - super(); - if (resourceId == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID"); - } - mResourceId = resourceId; - mPid = Binder.getCallingPid(); - mUid = Binder.getCallingUid(); - - getResourceTracker().take(); - } - - @Override - public abstract void invalidate() throws RemoteException; - - /** Convenience method; retrieves the user resource record for the stored UID. */ - protected UserRecord getUserRecord() { - return mUserResourceTracker.getUserRecord(mUid); - } - - @Override - public abstract void freeUnderlyingResources() throws RemoteException; - - /** Get the resource tracker for this resource */ - protected abstract ResourceTracker getResourceTracker(); - - @Override - public String toString() { - return new StringBuilder() - .append("{mResourceId=") - .append(mResourceId) - .append(", pid=") - .append(mPid) - .append(", uid=") - .append(mUid) - .append("}") - .toString(); - } - }; - - /** - * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing. - * - * <p>RefcountedResourceArray prevents null insertions, and throws an IllegalArgumentException - * if a key is not found during a retrieval process. - */ - static class RefcountedResourceArray<T extends IResource> { - SparseArray<RefcountedResource<T>> mArray = new SparseArray<>(); - private final String mTypeName; - - RefcountedResourceArray(String typeName) { - this.mTypeName = typeName; - } - - /** - * Accessor method to get inner resource object. - * - * @throws IllegalArgumentException if no resource with provided key is found. - */ - T getResourceOrThrow(int key) { - return getRefcountedResourceOrThrow(key).getResource(); - } - - /** - * Accessor method to get reference counting wrapper. - * - * @throws IllegalArgumentException if no resource with provided key is found. - */ - RefcountedResource<T> getRefcountedResourceOrThrow(int key) { - RefcountedResource<T> resource = mArray.get(key); - if (resource == null) { - throw new IllegalArgumentException( - String.format("No such %s found for given id: %d", mTypeName, key)); - } - - return resource; - } - - void put(int key, RefcountedResource<T> obj) { - Objects.requireNonNull(obj, "Null resources cannot be added"); - mArray.put(key, obj); - } - - void remove(int key) { - mArray.remove(key); - } - - @Override - public String toString() { - return mArray.toString(); - } - } - - /** - * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is - * created, the SpiRecord that originally tracked the SAs will reliquish the - * responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag. - */ - private final class TransformRecord extends OwnedResourceRecord { - private final IpSecConfig mConfig; - private final SpiRecord mSpi; - private final EncapSocketRecord mSocket; - - TransformRecord( - int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) { - super(resourceId); - mConfig = config; - mSpi = spi; - mSocket = socket; - - spi.setOwnedByTransform(); - } - - public IpSecConfig getConfig() { - return mConfig; - } - - public SpiRecord getSpiRecord() { - return mSpi; - } - - public EncapSocketRecord getSocketRecord() { - return mSocket; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - int spi = mSpi.getSpi(); - try { - mNetd.ipSecDeleteSecurityAssociation( - mUid, - mConfig.getSourceAddress(), - mConfig.getDestinationAddress(), - spi, - mConfig.getMarkValue(), - mConfig.getMarkMask(), - mConfig.getXfrmInterfaceId()); - } catch (RemoteException | ServiceSpecificException e) { - Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); - } - - getResourceTracker().give(); - } - - @Override - public void invalidate() throws RemoteException { - getUserRecord().removeTransformRecord(mResourceId); - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mTransformQuotaTracker; - } - - @Override - public String toString() { - StringBuilder strBuilder = new StringBuilder(); - strBuilder - .append("{super=") - .append(super.toString()) - .append(", mSocket=") - .append(mSocket) - .append(", mSpi.mResourceId=") - .append(mSpi.mResourceId) - .append(", mConfig=") - .append(mConfig) - .append("}"); - return strBuilder.toString(); - } - } - - /** - * Tracks a single SA in the kernel, and manages cleanup paths. Once used in a Transform, the - * responsibility for cleaning up underlying resources will be passed to the TransformRecord - * object - */ - private final class SpiRecord extends OwnedResourceRecord { - private final String mSourceAddress; - private final String mDestinationAddress; - private int mSpi; - - private boolean mOwnedByTransform = false; - - SpiRecord(int resourceId, String sourceAddress, - String destinationAddress, int spi) { - super(resourceId); - mSourceAddress = sourceAddress; - mDestinationAddress = destinationAddress; - mSpi = spi; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - try { - if (!mOwnedByTransform) { - mNetd.ipSecDeleteSecurityAssociation( - mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, - 0 /* mask */, 0 /* if_id */); - } - } catch (ServiceSpecificException | RemoteException e) { - Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); - } - - mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - - getResourceTracker().give(); - } - - public int getSpi() { - return mSpi; - } - - public String getDestinationAddress() { - return mDestinationAddress; - } - - public void setOwnedByTransform() { - if (mOwnedByTransform) { - // Programming error - throw new IllegalStateException("Cannot own an SPI twice!"); - } - - mOwnedByTransform = true; - } - - public boolean getOwnedByTransform() { - return mOwnedByTransform; - } - - @Override - public void invalidate() throws RemoteException { - getUserRecord().removeSpiRecord(mResourceId); - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mSpiQuotaTracker; - } - - @Override - public String toString() { - StringBuilder strBuilder = new StringBuilder(); - strBuilder - .append("{super=") - .append(super.toString()) - .append(", mSpi=") - .append(mSpi) - .append(", mSourceAddress=") - .append(mSourceAddress) - .append(", mDestinationAddress=") - .append(mDestinationAddress) - .append(", mOwnedByTransform=") - .append(mOwnedByTransform) - .append("}"); - return strBuilder.toString(); - } - } - - private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray(); - final Range<Integer> mNetIdRange = ConnectivityManager.getIpSecNetIdRange(); - private int mNextTunnelNetId = mNetIdRange.getLower(); - - /** - * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces - * - * <p>This method should only be called from Binder threads. Do not call this from within the - * system server as it will crash the system on failure. - * - * @return an integer key within the netId range, if successful - * @throws IllegalStateException if unsuccessful (all netId are currently reserved) - */ - @VisibleForTesting - int reserveNetId() { - final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1; - synchronized (mTunnelNetIds) { - for (int i = 0; i < range; i++) { - final int netId = mNextTunnelNetId; - if (++mNextTunnelNetId > mNetIdRange.getUpper()) { - mNextTunnelNetId = mNetIdRange.getLower(); - } - if (!mTunnelNetIds.get(netId)) { - mTunnelNetIds.put(netId, true); - return netId; - } - } - } - throw new IllegalStateException("No free netIds to allocate"); - } - - @VisibleForTesting - void releaseNetId(int netId) { - synchronized (mTunnelNetIds) { - mTunnelNetIds.delete(netId); - } - } - - /** - * Tracks an tunnel interface, and manages cleanup paths. - * - * <p>This class is not thread-safe, and expects that that users of this class will ensure - * synchronization and thread safety by holding the IpSecService.this instance lock - */ - @VisibleForTesting - final class TunnelInterfaceRecord extends OwnedResourceRecord { - private final String mInterfaceName; - - // outer addresses - private final String mLocalAddress; - private final String mRemoteAddress; - - private final int mIkey; - private final int mOkey; - - private final int mIfId; - - private Network mUnderlyingNetwork; - - TunnelInterfaceRecord( - int resourceId, - String interfaceName, - Network underlyingNetwork, - String localAddr, - String remoteAddr, - int ikey, - int okey, - int intfId) { - super(resourceId); - - mInterfaceName = interfaceName; - mUnderlyingNetwork = underlyingNetwork; - mLocalAddress = localAddr; - mRemoteAddress = remoteAddr; - mIkey = ikey; - mOkey = okey; - mIfId = intfId; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - // Calls to netd - // Teardown VTI - // Delete global policies - try { - mNetd.ipSecRemoveTunnelInterface(mInterfaceName); - - for (int selAddrFamily : ADDRESS_FAMILIES) { - mNetd.ipSecDeleteSecurityPolicy( - mUid, - selAddrFamily, - IpSecManager.DIRECTION_OUT, - mOkey, - 0xffffffff, - mIfId); - mNetd.ipSecDeleteSecurityPolicy( - mUid, - selAddrFamily, - IpSecManager.DIRECTION_IN, - mIkey, - 0xffffffff, - mIfId); - } - } catch (ServiceSpecificException | RemoteException e) { - Log.e( - TAG, - "Failed to delete VTI with interface name: " - + mInterfaceName - + " and id: " - + mResourceId, e); - } - - getResourceTracker().give(); - releaseNetId(mIkey); - releaseNetId(mOkey); - } - - @GuardedBy("IpSecService.this") - public void setUnderlyingNetwork(Network underlyingNetwork) { - // When #applyTunnelModeTransform is called, this new underlying network will be used to - // update the output mark of the input transform. - mUnderlyingNetwork = underlyingNetwork; - } - - @GuardedBy("IpSecService.this") - public Network getUnderlyingNetwork() { - return mUnderlyingNetwork; - } - - public String getInterfaceName() { - return mInterfaceName; - } - - /** Returns the local, outer address for the tunnelInterface */ - public String getLocalAddress() { - return mLocalAddress; - } - - /** Returns the remote, outer address for the tunnelInterface */ - public String getRemoteAddress() { - return mRemoteAddress; - } - - public int getIkey() { - return mIkey; - } - - public int getOkey() { - return mOkey; - } - - public int getIfId() { - return mIfId; - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mTunnelQuotaTracker; - } - - @Override - public void invalidate() { - getUserRecord().removeTunnelInterfaceRecord(mResourceId); - } - - @Override - public String toString() { - return new StringBuilder() - .append("{super=") - .append(super.toString()) - .append(", mInterfaceName=") - .append(mInterfaceName) - .append(", mUnderlyingNetwork=") - .append(mUnderlyingNetwork) - .append(", mLocalAddress=") - .append(mLocalAddress) - .append(", mRemoteAddress=") - .append(mRemoteAddress) - .append(", mIkey=") - .append(mIkey) - .append(", mOkey=") - .append(mOkey) - .append("}") - .toString(); - } - } - - /** - * Tracks a UDP encap socket, and manages cleanup paths - * - * <p>While this class does not manage non-kernel resources, race conditions around socket - * binding require that the service creates the encap socket, binds it and applies the socket - * policy before handing it to a user. - */ - private final class EncapSocketRecord extends OwnedResourceRecord { - private FileDescriptor mSocket; - private final int mPort; - - EncapSocketRecord(int resourceId, FileDescriptor socket, int port) { - super(resourceId); - mSocket = socket; - mPort = port; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - Log.d(TAG, "Closing port " + mPort); - IoUtils.closeQuietly(mSocket); - mSocket = null; - - getResourceTracker().give(); - } - - public int getPort() { - return mPort; - } - - public FileDescriptor getFileDescriptor() { - return mSocket; - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mSocketQuotaTracker; - } - - @Override - public void invalidate() { - getUserRecord().removeEncapSocketRecord(mResourceId); - } - - @Override - public String toString() { - return new StringBuilder() - .append("{super=") - .append(super.toString()) - .append(", mSocket=") - .append(mSocket) - .append(", mPort=") - .append(mPort) - .append("}") - .toString(); - } - } - - /** - * Constructs a new IpSecService instance - * - * @param context Binder context for this service - */ - public IpSecService(Context context) { - this(context, new Dependencies()); - } - - @NonNull - private AppOpsManager getAppOpsManager() { - AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); - if (appOps == null) throw new RuntimeException("System Server couldn't get AppOps"); - return appOps; - } - - /** @hide */ - @VisibleForTesting - public IpSecService(Context context, Dependencies deps) { - this( - context, - deps, - (fd, uid) -> { - try { - TrafficStats.setThreadStatsUid(uid); - TrafficStats.tagFileDescriptor(fd); - } finally { - TrafficStats.clearThreadStatsUid(); - } - }); - } - - /** @hide */ - @VisibleForTesting - public IpSecService(Context context, Dependencies deps, UidFdTagger uidFdTagger) { - mContext = context; - mDeps = Objects.requireNonNull(deps, "Missing dependencies."); - mUidFdTagger = uidFdTagger; - try { - mNetd = mDeps.getNetdInstance(mContext); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be - * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1. - */ - private static void checkInetAddress(String inetAddress) { - if (TextUtils.isEmpty(inetAddress)) { - throw new IllegalArgumentException("Unspecified address"); - } - - InetAddress checkAddr = InetAddresses.parseNumericAddress(inetAddress); - - if (checkAddr.isAnyLocalAddress()) { - throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress); - } - } - - /** - * Checks the user-provided direction field and throws an IllegalArgumentException if it is not - * DIRECTION_IN or DIRECTION_OUT - */ - private void checkDirection(int direction) { - switch (direction) { - case IpSecManager.DIRECTION_OUT: - case IpSecManager.DIRECTION_IN: - return; - case IpSecManager.DIRECTION_FWD: - // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies - PermissionUtils.enforceNetworkStackPermission(mContext); - return; - } - throw new IllegalArgumentException("Invalid Direction: " + direction); - } - - /** Get a new SPI and maintain the reservation in the system server */ - @Override - public synchronized IpSecSpiResponse allocateSecurityParameterIndex( - String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException { - checkInetAddress(destinationAddress); - // RFC 4303 Section 2.1 - 0=local, 1-255=reserved. - if (requestedSpi > 0 && requestedSpi < 256) { - throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255."); - } - Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); - - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - final int resourceId = mNextResourceId++; - - int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - try { - if (!userRecord.mSpiQuotaTracker.isAvailable()) { - return new IpSecSpiResponse( - IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); - } - - spi = mNetd.ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); - Log.d(TAG, "Allocated SPI " + spi); - userRecord.mSpiRecords.put( - resourceId, - new RefcountedResource<SpiRecord>( - new SpiRecord(resourceId, "", - destinationAddress, spi), binder)); - } catch (ServiceSpecificException e) { - if (e.errorCode == OsConstants.ENOENT) { - return new IpSecSpiResponse( - IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); - } - throw e; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi); - } - - /* This method should only be called from Binder threads. Do not call this from - * within the system server as it will crash the system on failure. - */ - private void releaseResource(RefcountedResourceArray resArray, int resourceId) - throws RemoteException { - resArray.getRefcountedResourceOrThrow(resourceId).userRelease(); - } - - /** Release a previously allocated SPI that has been registered with the system server */ - @Override - public synchronized void releaseSecurityParameterIndex(int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mSpiRecords, resourceId); - } - - /** - * This function finds and forcibly binds to a random system port, ensuring that the port cannot - * be unbound. - * - * <p>A socket cannot be un-bound from a port if it was bound to that port by number. To select - * a random open port and then bind by number, this function creates a temp socket, binds to a - * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP - * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned - * FileHandle. - * - * <p>The loop in this function handles the inherent race window between un-binding to a port - * and re-binding, during which the system could *technically* hand that port out to someone - * else. - */ - private int bindToRandomPort(FileDescriptor sockFd) throws IOException { - for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) { - try { - FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - Os.bind(probeSocket, INADDR_ANY, 0); - int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort(); - Os.close(probeSocket); - Log.v(TAG, "Binding to port " + port); - Os.bind(sockFd, INADDR_ANY, port); - return port; - } catch (ErrnoException e) { - // Someone miraculously claimed the port just after we closed probeSocket. - if (e.errno == OsConstants.EADDRINUSE) { - continue; - } - throw e.rethrowAsIOException(); - } - } - throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); - } - - /** - * Functional interface to do traffic tagging of given sockets to UIDs. - * - * <p>Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap - * sockets are billed to the UID that the UDP encap socket was created on behalf of. - * - * <p>Separate class so that the socket tagging logic can be mocked; TrafficStats uses static - * methods that cannot be easily mocked/tested. - */ - @VisibleForTesting - public interface UidFdTagger { - /** - * Sets socket tag to assign all traffic to the provided UID. - * - * <p>Since the socket is created on behalf of an unprivileged application, all traffic - * should be accounted to the UID of the unprivileged application. - */ - void tag(FileDescriptor fd, int uid) throws IOException; - } - - /** - * Open a socket via the system server and bind it to the specified port (random if port=0). - * This will return a PFD to the user that represent a bound UDP socket. The system server will - * cache the socket and a record of its owner so that it can and must be freed when no longer - * needed. - */ - @Override - public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder) - throws RemoteException { - if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) { - throw new IllegalArgumentException( - "Specified port number must be a valid non-reserved UDP port"); - } - Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); - - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - final int resourceId = mNextResourceId++; - - ParcelFileDescriptor pFd = null; - try { - if (!userRecord.mSocketQuotaTracker.isAvailable()) { - return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - FileDescriptor sockFd = null; - try { - sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - pFd = ParcelFileDescriptor.dup(sockFd); - } finally { - IoUtils.closeQuietly(sockFd); - } - - mUidFdTagger.tag(pFd.getFileDescriptor(), callingUid); - // This code is common to both the unspecified and specified port cases - Os.setsockoptInt( - pFd.getFileDescriptor(), - OsConstants.IPPROTO_UDP, - OsConstants.UDP_ENCAP, - OsConstants.UDP_ENCAP_ESPINUDP); - - mNetd.ipSecSetEncapSocketOwner(pFd, callingUid); - if (port != 0) { - Log.v(TAG, "Binding to port " + port); - Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port); - } else { - port = bindToRandomPort(pFd.getFileDescriptor()); - } - - userRecord.mEncapSocketRecords.put( - resourceId, - new RefcountedResource<EncapSocketRecord>( - new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port), - binder)); - return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, - pFd.getFileDescriptor()); - } catch (IOException | ErrnoException e) { - try { - if (pFd != null) { - pFd.close(); - } - } catch (IOException ex) { - // Nothing can be done at this point - Log.e(TAG, "Failed to close pFd."); - } - } - // If we make it to here, then something has gone wrong and we couldn't open a socket. - // The only reasonable condition that would cause that is resource unavailable. - return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - /** close a socket that has been been allocated by and registered with the system server */ - @Override - public synchronized void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mEncapSocketRecords, resourceId); - } - - /** - * Create a tunnel interface for use in IPSec tunnel mode. The system server will cache the - * tunnel interface and a record of its owner so that it can and must be freed when no longer - * needed. - */ - @Override - public synchronized IpSecTunnelInterfaceResponse createTunnelInterface( - String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, - String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface"); - Objects.requireNonNull(underlyingNetwork, "No underlying network was specified"); - checkInetAddress(localAddr); - checkInetAddress(remoteAddr); - - // TODO: Check that underlying network exists, and IP addresses not assigned to a different - // network (b/72316676). - - int callerUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid); - if (!userRecord.mTunnelQuotaTracker.isAvailable()) { - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - final int resourceId = mNextResourceId++; - final int ikey = reserveNetId(); - final int okey = reserveNetId(); - String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId); - - try { - // Calls to netd: - // Create VTI - // Add inbound/outbound global policies - // (use reqid = 0) - mNetd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); - - BinderUtils.withCleanCallingIdentity(() -> { - NetdUtils.setInterfaceUp(mNetd, intfName); - }); - - for (int selAddrFamily : ADDRESS_FAMILIES) { - // Always send down correct local/remote addresses for template. - mNetd.ipSecAddSecurityPolicy( - callerUid, - selAddrFamily, - IpSecManager.DIRECTION_OUT, - localAddr, - remoteAddr, - 0, - okey, - 0xffffffff, - resourceId); - mNetd.ipSecAddSecurityPolicy( - callerUid, - selAddrFamily, - IpSecManager.DIRECTION_IN, - remoteAddr, - localAddr, - 0, - ikey, - 0xffffffff, - resourceId); - - // Add a forwarding policy on the tunnel interface. In order to support forwarding - // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA. - // - // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD, - // forwarding will be blocked by default (as would be the case if this policy was - // absent). - // - // This is necessary only on the tunnel interface, and not any the interface to - // which traffic will be forwarded to. - mNetd.ipSecAddSecurityPolicy( - callerUid, - selAddrFamily, - IpSecManager.DIRECTION_FWD, - remoteAddr, - localAddr, - 0, - ikey, - 0xffffffff, - resourceId); - } - - userRecord.mTunnelInterfaceRecords.put( - resourceId, - new RefcountedResource<TunnelInterfaceRecord>( - new TunnelInterfaceRecord( - resourceId, - intfName, - underlyingNetwork, - localAddr, - remoteAddr, - ikey, - okey, - resourceId), - binder)); - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); - } catch (RemoteException e) { - // Release keys if we got an error. - releaseNetId(ikey); - releaseNetId(okey); - throw e.rethrowFromSystemServer(); - } catch (Throwable t) { - // Release keys if we got an error. - releaseNetId(ikey); - releaseNetId(okey); - throw t; - } - } - - /** - * Adds a new local address to the tunnel interface. This allows packets to be sent and received - * from multiple local IP addresses over the same tunnel. - */ - @Override - public synchronized void addAddressToTunnelInterface( - int tunnelResourceId, LinkAddress localAddr, String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException - TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - try { - // We can assume general validity of the IP address, since we get them as a - // LinkAddress, which does some validation. - mNetd.interfaceAddAddress( - tunnelInterfaceInfo.mInterfaceName, - localAddr.getAddress().getHostAddress(), - localAddr.getPrefixLength()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove a new local address from the tunnel interface. After removal, the address will no - * longer be available to send from, or receive on. - */ - @Override - public synchronized void removeAddressFromTunnelInterface( - int tunnelResourceId, LinkAddress localAddr, String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException - TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - try { - // We can assume general validity of the IP address, since we get them as a - // LinkAddress, which does some validation. - mNetd.interfaceDelAddress( - tunnelInterfaceInfo.mInterfaceName, - localAddr.getAddress().getHostAddress(), - localAddr.getPrefixLength()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** Set TunnelInterface to use a specific underlying network. */ - @Override - public synchronized void setNetworkForTunnelInterface( - int tunnelResourceId, Network underlyingNetwork, String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - Objects.requireNonNull(underlyingNetwork, "No underlying network was specified"); - - final UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException. userRecord.mTunnelInterfaceRecords is never null - final TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - final ConnectivityManager connectivityManager = - mContext.getSystemService(ConnectivityManager.class); - final LinkProperties lp = connectivityManager.getLinkProperties(underlyingNetwork); - if (tunnelInterfaceInfo.getInterfaceName().equals(lp.getInterfaceName())) { - throw new IllegalArgumentException( - "Underlying network cannot be the network being exposed by this tunnel"); - } - - // It is meaningless to check if the network exists or is valid because the network might - // disconnect at any time after it passes the check. - - tunnelInterfaceInfo.setUnderlyingNetwork(underlyingNetwork); - } - - /** - * Delete a TunnelInterface that has been been allocated by and registered with the system - * server - */ - @Override - public synchronized void deleteTunnelInterface( - int resourceId, String callingPackage) throws RemoteException { - enforceTunnelFeatureAndPermissions(callingPackage); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mTunnelInterfaceRecords, resourceId); - } - - @VisibleForTesting - void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException { - IpSecAlgorithm auth = config.getAuthentication(); - IpSecAlgorithm crypt = config.getEncryption(); - IpSecAlgorithm aead = config.getAuthenticatedEncryption(); - - // Validate the algorithm set - Preconditions.checkArgument( - aead != null || crypt != null || auth != null, - "No Encryption or Authentication algorithms specified"); - Preconditions.checkArgument( - auth == null || auth.isAuthentication(), - "Unsupported algorithm for Authentication"); - Preconditions.checkArgument( - crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption"); - Preconditions.checkArgument( - aead == null || aead.isAead(), - "Unsupported algorithm for Authenticated Encryption"); - Preconditions.checkArgument( - aead == null || (auth == null && crypt == null), - "Authenticated Encryption is mutually exclusive with other Authentication " - + "or Encryption algorithms"); - } - - private int getFamily(String inetAddress) { - int family = AF_UNSPEC; - InetAddress checkAddress = InetAddresses.parseNumericAddress(inetAddress); - if (checkAddress instanceof Inet4Address) { - family = AF_INET; - } else if (checkAddress instanceof Inet6Address) { - family = AF_INET6; - } - return family; - } - - /** - * Checks an IpSecConfig parcel to ensure that the contents are valid and throws an - * IllegalArgumentException if they are not. - */ - private void checkIpSecConfig(IpSecConfig config) { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - - switch (config.getEncapType()) { - case IpSecTransform.ENCAP_NONE: - break; - case IpSecTransform.ENCAP_ESPINUDP: - case IpSecTransform.ENCAP_ESPINUDP_NON_IKE: - // Retrieve encap socket record; will throw IllegalArgumentException if not found - userRecord.mEncapSocketRecords.getResourceOrThrow( - config.getEncapSocketResourceId()); - - int port = config.getEncapRemotePort(); - if (port <= 0 || port > 0xFFFF) { - throw new IllegalArgumentException("Invalid remote UDP port: " + port); - } - break; - default: - throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType()); - } - - validateAlgorithms(config); - - // Retrieve SPI record; will throw IllegalArgumentException if not found - SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId()); - - // Check to ensure that SPI has not already been used. - if (s.getOwnedByTransform()) { - throw new IllegalStateException("SPI already in use; cannot be used in new Transforms"); - } - - // If no remote address is supplied, then use one from the SPI. - if (TextUtils.isEmpty(config.getDestinationAddress())) { - config.setDestinationAddress(s.getDestinationAddress()); - } - - // All remote addresses must match - if (!config.getDestinationAddress().equals(s.getDestinationAddress())) { - throw new IllegalArgumentException("Mismatched remote addresseses."); - } - - // This check is technically redundant due to the chain of custody between the SPI and - // the IpSecConfig, but in the future if the dest is allowed to be set explicitly in - // the transform, this will prevent us from messing up. - checkInetAddress(config.getDestinationAddress()); - - // Require a valid source address for all transforms. - checkInetAddress(config.getSourceAddress()); - - // Check to ensure source and destination have the same address family. - String sourceAddress = config.getSourceAddress(); - String destinationAddress = config.getDestinationAddress(); - int sourceFamily = getFamily(sourceAddress); - int destinationFamily = getFamily(destinationAddress); - if (sourceFamily != destinationFamily) { - throw new IllegalArgumentException( - "Source address (" - + sourceAddress - + ") and destination address (" - + destinationAddress - + ") have different address families."); - } - - // Throw an error if UDP Encapsulation is not used in IPv4. - if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) { - throw new IllegalArgumentException( - "UDP Encapsulation is not supported for this address family"); - } - - switch (config.getMode()) { - case IpSecTransform.MODE_TRANSPORT: - break; - case IpSecTransform.MODE_TUNNEL: - break; - default: - throw new IllegalArgumentException( - "Invalid IpSecTransform.mode: " + config.getMode()); - } - - config.setMarkValue(0); - config.setMarkMask(0); - } - - private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS; - - private void enforceTunnelFeatureAndPermissions(String callingPackage) { - if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) { - throw new UnsupportedOperationException( - "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS"); - } - - Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - - // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system - // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS - // permission or is the System Server. - if (AppOpsManager.MODE_ALLOWED == getAppOpsManager().noteOpNoThrow( - TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { - return; - } - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - } - - private void createOrUpdateTransform( - IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord) - throws RemoteException { - - int encapType = c.getEncapType(), encapLocalPort = 0, encapRemotePort = 0; - if (encapType != IpSecTransform.ENCAP_NONE) { - encapLocalPort = socketRecord.getPort(); - encapRemotePort = c.getEncapRemotePort(); - } - - IpSecAlgorithm auth = c.getAuthentication(); - IpSecAlgorithm crypt = c.getEncryption(); - IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); - - String cryptName; - if (crypt == null) { - cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : ""; - } else { - cryptName = crypt.getName(); - } - - mNetd.ipSecAddSecurityAssociation( - Binder.getCallingUid(), - c.getMode(), - c.getSourceAddress(), - c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, - spiRecord.getSpi(), - c.getMarkValue(), - c.getMarkMask(), - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : new byte[] {}, - (auth != null) ? auth.getTruncationLengthBits() : 0, - cryptName, - (crypt != null) ? crypt.getKey() : new byte[] {}, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, - (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort, - c.getXfrmInterfaceId()); - } - - /** - * Create a IPsec transform, which represents a single security association in the kernel. The - * transform will be cached by the system server and must be freed when no longer needed. It is - * possible to free one, deleting the SA from underneath sockets that are using it, which will - * result in all of those sockets becoming unable to send or receive data. - */ - @Override - public synchronized IpSecTransformResponse createTransform( - IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { - Objects.requireNonNull(c); - if (c.getMode() == IpSecTransform.MODE_TUNNEL) { - enforceTunnelFeatureAndPermissions(callingPackage); - } - checkIpSecConfig(c); - Objects.requireNonNull(binder, "Null Binder passed to createTransform"); - final int resourceId = mNextResourceId++; - - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - List<RefcountedResource> dependencies = new ArrayList<>(); - - if (!userRecord.mTransformQuotaTracker.isAvailable()) { - return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - EncapSocketRecord socketRecord = null; - if (c.getEncapType() != IpSecTransform.ENCAP_NONE) { - RefcountedResource<EncapSocketRecord> refcountedSocketRecord = - userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow( - c.getEncapSocketResourceId()); - dependencies.add(refcountedSocketRecord); - socketRecord = refcountedSocketRecord.getResource(); - } - - RefcountedResource<SpiRecord> refcountedSpiRecord = - userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId()); - dependencies.add(refcountedSpiRecord); - SpiRecord spiRecord = refcountedSpiRecord.getResource(); - - createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); - - // SA was created successfully, time to construct a record and lock it away - userRecord.mTransformRecords.put( - resourceId, - new RefcountedResource<TransformRecord>( - new TransformRecord(resourceId, c, spiRecord, socketRecord), - binder, - dependencies.toArray(new RefcountedResource[dependencies.size()]))); - return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); - } - - /** - * Delete a transport mode transform that was previously allocated by + registered with the - * system server. If this is called on an inactive (or non-existent) transform, it will not - * return an error. It's safe to de-allocate transforms that may have already been deleted for - * other reasons. - */ - @Override - public synchronized void deleteTransform(int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mTransformRecords, resourceId); - } - - /** - * Apply an active transport mode transform to a socket, which will apply the IPsec security - * association as a correspondent policy to the provided socket - */ - @Override - public synchronized void applyTransportModeTransform( - ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException { - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - checkDirection(direction); - // Get transform record; if no transform is found, will throw IllegalArgumentException - TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); - - // TODO: make this a function. - if (info.mPid != getCallingPid() || info.mUid != callingUid) { - throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); - } - - // Get config and check that to-be-applied transform has the correct mode - IpSecConfig c = info.getConfig(); - Preconditions.checkArgument( - c.getMode() == IpSecTransform.MODE_TRANSPORT, - "Transform mode was not Transport mode; cannot be applied to a socket"); - - mNetd.ipSecApplyTransportModeTransform( - socket, - callingUid, - direction, - c.getSourceAddress(), - c.getDestinationAddress(), - info.getSpiRecord().getSpi()); - } - - /** - * Remove transport mode transforms from a socket, applying the default (empty) policy. This - * ensures that NO IPsec policy is applied to the socket (would be the equivalent of applying a - * policy that performs no IPsec). Today the resourceId parameter is passed but not used: - * reserved for future improved input validation. - */ - @Override - public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) - throws RemoteException { - mNetd.ipSecRemoveTransportModeTransform(socket); - } - - /** - * Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec - * security association as a correspondent policy to the provided interface - */ - @Override - public synchronized void applyTunnelModeTransform( - int tunnelResourceId, int direction, - int transformResourceId, String callingPackage) throws RemoteException { - enforceTunnelFeatureAndPermissions(callingPackage); - checkDirection(direction); - - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - - // Get transform record; if no transform is found, will throw IllegalArgumentException - TransformRecord transformInfo = - userRecord.mTransformRecords.getResourceOrThrow(transformResourceId); - - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException - TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - // Get config and check that to-be-applied transform has the correct mode - IpSecConfig c = transformInfo.getConfig(); - Preconditions.checkArgument( - c.getMode() == IpSecTransform.MODE_TUNNEL, - "Transform mode was not Tunnel mode; cannot be applied to a tunnel interface"); - - EncapSocketRecord socketRecord = null; - if (c.getEncapType() != IpSecTransform.ENCAP_NONE) { - socketRecord = - userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId()); - } - SpiRecord spiRecord = transformInfo.getSpiRecord(); - - int mark = - (direction == IpSecManager.DIRECTION_OUT) - ? tunnelInterfaceInfo.getOkey() - : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies - - try { - // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip - // SPI matching as part of the template resolution. - int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId()); - - // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream - // (and backporting) would allow us to narrow the mark space, and ensure that the SA - // and SPs have matching marks (as VTI are meant to be built). - // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the - // config matches the actual allocated resources in the kernel. - // All SAs will have zero marks (from creation time), and any policy that matches the - // same src/dst could match these SAs. Non-IpSecService governed processes that - // establish floating policies with the same src/dst may result in undefined - // behavior. This is generally limited to vendor code due to the permissions - // (CAP_NET_ADMIN) required. - // - // c.setMarkValue(mark); - // c.setMarkMask(0xffffffff); - - if (direction == IpSecManager.DIRECTION_OUT) { - // Set output mark via underlying network (output only) - c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork()); - - // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys, - // but want to guarantee outbound packets are sent over the new SA. - spi = spiRecord.getSpi(); - } - - // Always update the policy with the relevant XFRM_IF_ID - for (int selAddrFamily : ADDRESS_FAMILIES) { - mNetd.ipSecUpdateSecurityPolicy( - callingUid, - selAddrFamily, - direction, - transformInfo.getConfig().getSourceAddress(), - transformInfo.getConfig().getDestinationAddress(), - spi, // If outbound, also add SPI to the policy. - mark, // Must always set policy mark; ikey/okey for VTIs - 0xffffffff, - c.getXfrmInterfaceId()); - } - - // Update SA with tunnel mark (ikey or okey based on direction) - createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord); - } catch (ServiceSpecificException e) { - if (e.errorCode == EINVAL) { - throw new IllegalArgumentException(e.toString()); - } else { - throw e; - } - } - } - - @Override - protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mContext.enforceCallingOrSelfPermission(DUMP, TAG); - - pw.println("IpSecService dump:"); - pw.println(); - - pw.println("mUserResourceTracker:"); - pw.println(mUserResourceTracker); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java deleted file mode 100644 index ec8d7798e17e..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.os.Build; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.SystemClock; -import android.util.LocalLog; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Objects; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Generic connector class for interfacing with a native daemon which uses the - * {@code libsysutils} FrameworkListener protocol. - */ -final class NativeDaemonConnector implements Runnable, Handler.Callback { - private final static boolean VDBG = false; - - private final String TAG; - - private String mSocket; - private OutputStream mOutputStream; - private LocalLog mLocalLog; - - private volatile boolean mDebug = false; - private volatile Object mWarnIfHeld; - - private final ResponseQueue mResponseQueue; - - private final PowerManager.WakeLock mWakeLock; - - private final Looper mLooper; - - private INativeDaemonConnectorCallbacks mCallbacks; - private Handler mCallbackHandler; - - private AtomicInteger mSequenceNumber; - - private static final long DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ - private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */ - - /** Lock held whenever communicating with native daemon. */ - private final Object mDaemonLock = new Object(); - - private final int BUFFER_SIZE = 4096; - - NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, - int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) { - mCallbacks = callbacks; - mSocket = socket; - mResponseQueue = new ResponseQueue(responseQueueSize); - mWakeLock = wl; - if (mWakeLock != null) { - mWakeLock.setReferenceCounted(true); - } - mSequenceNumber = new AtomicInteger(0); - TAG = logTag != null ? logTag : "NativeDaemonConnector"; - mLocalLog = new LocalLog(maxLogSize); - final HandlerThread thread = new HandlerThread(TAG); - thread.start(); - mLooper = thread.getLooper(); - } - - /** - * Enable Set debugging mode, which causes messages to also be written to both - * {@link Log} in addition to internal log. - */ - public void setDebug(boolean debug) { - mDebug = debug; - } - - /** - * Like SystemClock.uptimeMillis, except truncated to an int so it will fit in a message arg. - * Inaccurate across 49.7 days of uptime, but only used for debugging. - */ - private int uptimeMillisInt() { - return (int) SystemClock.uptimeMillis() & Integer.MAX_VALUE; - } - - /** - * Yell loudly if someone tries making future {@link #execute(Command)} - * calls while holding a lock on the given object. - */ - public void setWarnIfHeld(Object warnIfHeld) { - if (mWarnIfHeld != null) { - throw new IllegalStateException("warnIfHeld is already set."); - } - mWarnIfHeld = Objects.requireNonNull(warnIfHeld); - } - - @Override - public void run() { - mCallbackHandler = new Handler(mLooper, this); - - while (true) { - try { - listenToSocket(); - } catch (Exception e) { - loge("Error in NativeDaemonConnector: " + e); - SystemClock.sleep(5000); - } - } - } - - @Override - public boolean handleMessage(Message msg) { - final String event = (String) msg.obj; - final int start = uptimeMillisInt(); - final int sent = msg.arg1; - try { - if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { - log(String.format("Unhandled event '%s'", event)); - } - } catch (Exception e) { - loge("Error handling '" + event + "': " + e); - } finally { - if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) { - mWakeLock.release(); - } - final int end = uptimeMillisInt(); - if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) { - loge(String.format("NDC event {%s} processed too late: %dms", event, start - sent)); - } - if (end > start && end - start > WARN_EXECUTE_DELAY_MS) { - loge(String.format("NDC event {%s} took too long: %dms", event, end - start)); - } - } - return true; - } - - private LocalSocketAddress determineSocketAddress() { - // If we're testing, set up a socket in a namespace that's accessible to test code. - // In order to ensure that unprivileged apps aren't able to impersonate native daemons on - // production devices, even if said native daemons ill-advisedly pick a socket name that - // starts with __test__, only allow this on debug builds. - if (mSocket.startsWith("__test__") && Build.isDebuggable()) { - return new LocalSocketAddress(mSocket); - } else { - return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); - } - } - - private void listenToSocket() throws IOException { - LocalSocket socket = null; - - try { - socket = new LocalSocket(); - LocalSocketAddress address = determineSocketAddress(); - - socket.connect(address); - - InputStream inputStream = socket.getInputStream(); - synchronized (mDaemonLock) { - mOutputStream = socket.getOutputStream(); - } - - mCallbacks.onDaemonConnected(); - - FileDescriptor[] fdList = null; - byte[] buffer = new byte[BUFFER_SIZE]; - int start = 0; - - while (true) { - int count = inputStream.read(buffer, start, BUFFER_SIZE - start); - if (count < 0) { - loge("got " + count + " reading with start = " + start); - break; - } - fdList = socket.getAncillaryFileDescriptors(); - - // Add our starting point to the count and reset the start. - count += start; - start = 0; - - for (int i = 0; i < count; i++) { - if (buffer[i] == 0) { - // Note - do not log this raw message since it may contain - // sensitive data - final String rawEvent = new String( - buffer, start, i - start, StandardCharsets.UTF_8); - - boolean releaseWl = false; - try { - final NativeDaemonEvent event = - NativeDaemonEvent.parseRawEvent(rawEvent, fdList); - - log("RCV <- {" + event + "}"); - - if (event.isClassUnsolicited()) { - // TODO: migrate to sending NativeDaemonEvent instances - if (mCallbacks.onCheckHoldWakeLock(event.getCode()) - && mWakeLock != null) { - mWakeLock.acquire(); - releaseWl = true; - } - Message msg = mCallbackHandler.obtainMessage( - event.getCode(), uptimeMillisInt(), 0, event.getRawEvent()); - if (mCallbackHandler.sendMessage(msg)) { - releaseWl = false; - } - } else { - mResponseQueue.add(event.getCmdNumber(), event); - } - } catch (IllegalArgumentException e) { - log("Problem parsing message " + e); - } finally { - if (releaseWl) { - mWakeLock.release(); - } - } - - start = i + 1; - } - } - - if (start == 0) { - log("RCV incomplete"); - } - - // We should end at the amount we read. If not, compact then - // buffer and read again. - if (start != count) { - final int remaining = BUFFER_SIZE - start; - System.arraycopy(buffer, start, buffer, 0, remaining); - start = remaining; - } else { - start = 0; - } - } - } catch (IOException ex) { - loge("Communications error: " + ex); - throw ex; - } finally { - synchronized (mDaemonLock) { - if (mOutputStream != null) { - try { - loge("closing stream for " + mSocket); - mOutputStream.close(); - } catch (IOException e) { - loge("Failed closing output stream: " + e); - } - mOutputStream = null; - } - } - - try { - if (socket != null) { - socket.close(); - } - } catch (IOException ex) { - loge("Failed closing socket: " + ex); - } - } - } - - /** - * Wrapper around argument that indicates it's sensitive and shouldn't be - * logged. - */ - public static class SensitiveArg { - private final Object mArg; - - public SensitiveArg(Object arg) { - mArg = arg; - } - - @Override - public String toString() { - return String.valueOf(mArg); - } - } - - /** - * Make command for daemon, escaping arguments as needed. - */ - @VisibleForTesting - static void makeCommand(StringBuilder rawBuilder, StringBuilder logBuilder, int sequenceNumber, - String cmd, Object... args) { - if (cmd.indexOf('\0') >= 0) { - throw new IllegalArgumentException("Unexpected command: " + cmd); - } - if (cmd.indexOf(' ') >= 0) { - throw new IllegalArgumentException("Arguments must be separate from command"); - } - - rawBuilder.append(sequenceNumber).append(' ').append(cmd); - logBuilder.append(sequenceNumber).append(' ').append(cmd); - for (Object arg : args) { - final String argString = String.valueOf(arg); - if (argString.indexOf('\0') >= 0) { - throw new IllegalArgumentException("Unexpected argument: " + arg); - } - - rawBuilder.append(' '); - logBuilder.append(' '); - - appendEscaped(rawBuilder, argString); - if (arg instanceof SensitiveArg) { - logBuilder.append("[scrubbed]"); - } else { - appendEscaped(logBuilder, argString); - } - } - - rawBuilder.append('\0'); - } - - /** - * Method that waits until all asychronous notifications sent by the native daemon have - * been processed. This method must not be called on the notification thread or an - * exception will be thrown. - */ - public void waitForCallbacks() { - if (Thread.currentThread() == mLooper.getThread()) { - throw new IllegalStateException("Must not call this method on callback thread"); - } - - final CountDownLatch latch = new CountDownLatch(1); - mCallbackHandler.post(new Runnable() { - @Override - public void run() { - latch.countDown(); - } - }); - try { - latch.await(); - } catch (InterruptedException e) { - Log.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e); - } - } - - /** - * Issue the given command to the native daemon and return a single expected - * response. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent execute(Command cmd) throws NativeDaemonConnectorException { - return execute(cmd.mCmd, cmd.mArguments.toArray()); - } - - /** - * Issue the given command to the native daemon and return a single expected - * response. Any arguments must be separated from base command so they can - * be properly escaped. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent execute(String cmd, Object... args) - throws NativeDaemonConnectorException { - return execute(DEFAULT_TIMEOUT, cmd, args); - } - - public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args) - throws NativeDaemonConnectorException { - final NativeDaemonEvent[] events = executeForList(timeoutMs, cmd, args); - if (events.length != 1) { - throw new NativeDaemonConnectorException( - "Expected exactly one response, but received " + events.length); - } - return events[0]; - } - - /** - * Issue the given command to the native daemon and return any - * {@link NativeDaemonEvent#isClassContinue()} responses, including the - * final terminal response. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] executeForList(Command cmd) throws NativeDaemonConnectorException { - return executeForList(cmd.mCmd, cmd.mArguments.toArray()); - } - - /** - * Issue the given command to the native daemon and return any - * {@link NativeDaemonEvent#isClassContinue()} responses, including the - * final terminal response. Any arguments must be separated from base - * command so they can be properly escaped. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] executeForList(String cmd, Object... args) - throws NativeDaemonConnectorException { - return executeForList(DEFAULT_TIMEOUT, cmd, args); - } - - /** - * Issue the given command to the native daemon and return any {@linke - * NativeDaemonEvent@isClassContinue()} responses, including the final - * terminal response. Note that the timeout does not count time in deep - * sleep. Any arguments must be separated from base command so they can be - * properly escaped. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) - throws NativeDaemonConnectorException { - if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { - Log.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" - + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); - } - - final long startTime = SystemClock.elapsedRealtime(); - - final ArrayList<NativeDaemonEvent> events = new ArrayList<>(); - - final StringBuilder rawBuilder = new StringBuilder(); - final StringBuilder logBuilder = new StringBuilder(); - final int sequenceNumber = mSequenceNumber.incrementAndGet(); - - makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args); - - final String rawCmd = rawBuilder.toString(); - final String logCmd = logBuilder.toString(); - - log("SND -> {" + logCmd + "}"); - - synchronized (mDaemonLock) { - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); - } - } - } - - NativeDaemonEvent event = null; - do { - event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd); - if (event == null) { - loge("timed-out waiting for response to " + logCmd); - throw new NativeDaemonTimeoutException(logCmd, event); - } - if (VDBG) log("RMV <- {" + event + "}"); - events.add(event); - } while (event.isClassContinue()); - - final long endTime = SystemClock.elapsedRealtime(); - if (endTime - startTime > WARN_EXECUTE_DELAY_MS) { - loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)"); - } - - if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(logCmd, event); - } - if (event.isClassServerError()) { - throw new NativeDaemonFailureException(logCmd, event); - } - - return events.toArray(new NativeDaemonEvent[events.size()]); - } - - /** - * Append the given argument to {@link StringBuilder}, escaping as needed, - * and surrounding with quotes when it contains spaces. - */ - @VisibleForTesting - static void appendEscaped(StringBuilder builder, String arg) { - final boolean hasSpaces = arg.indexOf(' ') >= 0; - if (hasSpaces) { - builder.append('"'); - } - - final int length = arg.length(); - for (int i = 0; i < length; i++) { - final char c = arg.charAt(i); - - if (c == '"') { - builder.append("\\\""); - } else if (c == '\\') { - builder.append("\\\\"); - } else { - builder.append(c); - } - } - - if (hasSpaces) { - builder.append('"'); - } - } - - private static class NativeDaemonArgumentException extends NativeDaemonConnectorException { - public NativeDaemonArgumentException(String command, NativeDaemonEvent event) { - super(command, event); - } - - @Override - public IllegalArgumentException rethrowAsParcelableException() { - throw new IllegalArgumentException(getMessage(), this); - } - } - - private static class NativeDaemonFailureException extends NativeDaemonConnectorException { - public NativeDaemonFailureException(String command, NativeDaemonEvent event) { - super(command, event); - } - } - - /** - * Command builder that handles argument list building. Any arguments must - * be separated from base command so they can be properly escaped. - */ - public static class Command { - private String mCmd; - private ArrayList<Object> mArguments = new ArrayList<>(); - - public Command(String cmd, Object... args) { - mCmd = cmd; - for (Object arg : args) { - appendArg(arg); - } - } - - public Command appendArg(Object arg) { - mArguments.add(arg); - return this; - } - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mLocalLog.dump(fd, pw, args); - pw.println(); - mResponseQueue.dump(fd, pw, args); - } - - private void log(String logstring) { - if (mDebug) Log.d(TAG, logstring); - mLocalLog.log(logstring); - } - - private void loge(String logstring) { - Log.e(TAG, logstring); - mLocalLog.log(logstring); - } - - private static class ResponseQueue { - - private static class PendingCmd { - public final int cmdNum; - public final String logCmd; - - public BlockingQueue<NativeDaemonEvent> responses = - new ArrayBlockingQueue<NativeDaemonEvent>(10); - - // The availableResponseCount member is used to track when we can remove this - // instance from the ResponseQueue. - // This is used under the protection of a sync of the mPendingCmds object. - // A positive value means we've had more writers retreive this object while - // a negative value means we've had more readers. When we've had an equal number - // (it goes to zero) we can remove this object from the mPendingCmds list. - // Note that we may have more responses for this command (and more readers - // coming), but that would result in a new PendingCmd instance being created - // and added with the same cmdNum. - // Also note that when this goes to zero it just means a parity of readers and - // writers have retrieved this object - not that they are done using it. The - // responses queue may well have more responses yet to be read or may get more - // responses added to it. But all those readers/writers have retreived and - // hold references to this instance already so it can be removed from - // mPendingCmds queue. - public int availableResponseCount; - - public PendingCmd(int cmdNum, String logCmd) { - this.cmdNum = cmdNum; - this.logCmd = logCmd; - } - } - - private final LinkedList<PendingCmd> mPendingCmds; - private int mMaxCount; - - ResponseQueue(int maxCount) { - mPendingCmds = new LinkedList<PendingCmd>(); - mMaxCount = maxCount; - } - - public void add(int cmdNum, NativeDaemonEvent response) { - PendingCmd found = null; - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - if (pendingCmd.cmdNum == cmdNum) { - found = pendingCmd; - break; - } - } - if (found == null) { - // didn't find it - make sure our queue isn't too big before adding - while (mPendingCmds.size() >= mMaxCount) { - Log.e("NativeDaemonConnector.ResponseQueue", - "more buffered than allowed: " + mPendingCmds.size() + - " >= " + mMaxCount); - // let any waiter timeout waiting for this - PendingCmd pendingCmd = mPendingCmds.remove(); - Log.e("NativeDaemonConnector.ResponseQueue", - "Removing request: " + pendingCmd.logCmd + " (" + - pendingCmd.cmdNum + ")"); - } - found = new PendingCmd(cmdNum, null); - mPendingCmds.add(found); - } - found.availableResponseCount++; - // if a matching remove call has already retrieved this we can remove this - // instance from our list - if (found.availableResponseCount == 0) mPendingCmds.remove(found); - } - try { - found.responses.put(response); - } catch (InterruptedException e) { } - } - - // note that the timeout does not count time in deep sleep. If you don't want - // the device to sleep, hold a wakelock - public NativeDaemonEvent remove(int cmdNum, long timeoutMs, String logCmd) { - PendingCmd found = null; - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - if (pendingCmd.cmdNum == cmdNum) { - found = pendingCmd; - break; - } - } - if (found == null) { - found = new PendingCmd(cmdNum, logCmd); - mPendingCmds.add(found); - } - found.availableResponseCount--; - // if a matching add call has already retrieved this we can remove this - // instance from our list - if (found.availableResponseCount == 0) mPendingCmds.remove(found); - } - NativeDaemonEvent result = null; - try { - result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) {} - if (result == null) { - Log.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response"); - } - return result; - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("Pending requests:"); - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.logCmd); - } - } - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java deleted file mode 100644 index 4d8881c68324..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package com.android.server; - -import android.os.Parcel; - -/** - * An exception that indicates there was an error with a - * {@link NativeDaemonConnector} operation. - */ -public class NativeDaemonConnectorException extends Exception { - private String mCmd; - private NativeDaemonEvent mEvent; - - public NativeDaemonConnectorException(String detailMessage) { - super(detailMessage); - } - - public NativeDaemonConnectorException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } - - public NativeDaemonConnectorException(String cmd, NativeDaemonEvent event) { - super("command '" + cmd + "' failed with '" + event + "'"); - mCmd = cmd; - mEvent = event; - } - - public int getCode() { - return mEvent != null ? mEvent.getCode() : -1; - } - - public String getCmd() { - return mCmd; - } - - /** - * Rethrow as a {@link RuntimeException} subclass that is handled by - * {@link Parcel#writeException(Exception)}. - */ - public IllegalArgumentException rethrowAsParcelableException() { - throw new IllegalStateException(getMessage(), this); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java deleted file mode 100644 index 568369434629..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.util.Log; - -import java.io.FileDescriptor; -import java.util.ArrayList; - -/** - * Parsed event from native side of {@link NativeDaemonConnector}. - */ -public class NativeDaemonEvent { - - // TODO: keep class ranges in sync with ResponseCode.h - // TODO: swap client and server error ranges to roughly mirror HTTP spec - - private final int mCmdNumber; - private final int mCode; - private final String mMessage; - private final String mRawEvent; - private final String mLogMessage; - private String[] mParsed; - private FileDescriptor[] mFdList; - - private NativeDaemonEvent(int cmdNumber, int code, String message, - String rawEvent, String logMessage, FileDescriptor[] fdList) { - mCmdNumber = cmdNumber; - mCode = code; - mMessage = message; - mRawEvent = rawEvent; - mLogMessage = logMessage; - mParsed = null; - mFdList = fdList; - } - - static public final String SENSITIVE_MARKER = "{{sensitive}}"; - - public int getCmdNumber() { - return mCmdNumber; - } - - public int getCode() { - return mCode; - } - - public String getMessage() { - return mMessage; - } - - public FileDescriptor[] getFileDescriptors() { - return mFdList; - } - - @Deprecated - public String getRawEvent() { - return mRawEvent; - } - - @Override - public String toString() { - return mLogMessage; - } - - /** - * Test if event represents a partial response which is continued in - * additional subsequent events. - */ - public boolean isClassContinue() { - return mCode >= 100 && mCode < 200; - } - - /** - * Test if event represents a command success. - */ - public boolean isClassOk() { - return mCode >= 200 && mCode < 300; - } - - /** - * Test if event represents a remote native daemon error. - */ - public boolean isClassServerError() { - return mCode >= 400 && mCode < 500; - } - - /** - * Test if event represents a command syntax or argument error. - */ - public boolean isClassClientError() { - return mCode >= 500 && mCode < 600; - } - - /** - * Test if event represents an unsolicited event from native daemon. - */ - public boolean isClassUnsolicited() { - return isClassUnsolicited(mCode); - } - - private static boolean isClassUnsolicited(int code) { - return code >= 600 && code < 700; - } - - /** - * Verify this event matches the given code. - * - * @throws IllegalStateException if {@link #getCode()} doesn't match. - */ - public void checkCode(int code) { - if (mCode != code) { - throw new IllegalStateException("Expected " + code + " but was: " + this); - } - } - - /** - * Parse the given raw event into {@link NativeDaemonEvent} instance. - * - * @throws IllegalArgumentException when line doesn't match format expected - * from native side. - */ - public static NativeDaemonEvent parseRawEvent(String rawEvent, FileDescriptor[] fdList) { - final String[] parsed = rawEvent.split(" "); - if (parsed.length < 2) { - throw new IllegalArgumentException("Insufficient arguments"); - } - - int skiplength = 0; - - final int code; - try { - code = Integer.parseInt(parsed[0]); - skiplength = parsed[0].length() + 1; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("problem parsing code", e); - } - - int cmdNumber = -1; - if (isClassUnsolicited(code) == false) { - if (parsed.length < 3) { - throw new IllegalArgumentException("Insufficient arguemnts"); - } - try { - cmdNumber = Integer.parseInt(parsed[1]); - skiplength += parsed[1].length() + 1; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("problem parsing cmdNumber", e); - } - } - - String logMessage = rawEvent; - if (parsed.length > 2 && parsed[2].equals(SENSITIVE_MARKER)) { - skiplength += parsed[2].length() + 1; - logMessage = parsed[0] + " " + parsed[1] + " {}"; - } - - final String message = rawEvent.substring(skiplength); - - return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage, fdList); - } - - /** - * Filter the given {@link NativeDaemonEvent} list, returning - * {@link #getMessage()} for any events matching the requested code. - */ - public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) { - final ArrayList<String> result = new ArrayList<>(); - for (NativeDaemonEvent event : events) { - if (event.getCode() == matchCode) { - result.add(event.getMessage()); - } - } - return result.toArray(new String[result.size()]); - } - - /** - * Find the Nth field of the event. - * - * This ignores and code or cmdNum, the first return value is given for N=0. - * Also understands "\"quoted\" multiword responses" and tries them as a single field - */ - public String getField(int n) { - if (mParsed == null) { - mParsed = unescapeArgs(mRawEvent); - } - n += 2; // skip code and command# - if (n > mParsed.length) return null; - return mParsed[n]; - } - - public static String[] unescapeArgs(String rawEvent) { - final boolean DEBUG_ROUTINE = false; - final String LOGTAG = "unescapeArgs"; - final ArrayList<String> parsed = new ArrayList<String>(); - final int length = rawEvent.length(); - int current = 0; - int wordEnd = -1; - boolean quoted = false; - - if (DEBUG_ROUTINE) Log.e(LOGTAG, "parsing '" + rawEvent + "'"); - if (rawEvent.charAt(current) == '\"') { - quoted = true; - current++; - } - while (current < length) { - // find the end of the word - char terminator = quoted ? '\"' : ' '; - wordEnd = current; - while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) { - if (rawEvent.charAt(wordEnd) == '\\') { - // skip the escaped char - ++wordEnd; - } - ++wordEnd; - } - if (wordEnd > length) wordEnd = length; - String word = rawEvent.substring(current, wordEnd); - current += word.length(); - if (!quoted) { - word = word.trim(); - } else { - current++; // skip the trailing quote - } - // unescape stuff within the word - word = word.replace("\\\\", "\\"); - word = word.replace("\\\"", "\""); - - if (DEBUG_ROUTINE) Log.e(LOGTAG, "found '" + word + "'"); - parsed.add(word); - - // find the beginning of the next word - either of these options - int nextSpace = rawEvent.indexOf(' ', current); - int nextQuote = rawEvent.indexOf(" \"", current); - if (DEBUG_ROUTINE) { - Log.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote); - } - if (nextQuote > -1 && nextQuote <= nextSpace) { - quoted = true; - current = nextQuote + 2; - } else { - quoted = false; - if (nextSpace > -1) { - current = nextSpace + 1; - } - } // else we just start the next word after the current and read til the end - if (DEBUG_ROUTINE) { - Log.e(LOGTAG, "next loop - current=" + current - + ", length=" + length + ", quoted=" + quoted); - } - } - return parsed.toArray(new String[parsed.size()]); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java deleted file mode 100644 index 658f7d6264eb..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -/** - * An exception that indicates there was a timeout with a - * {@link NativeDaemonConnector} operation. - */ -public class NativeDaemonTimeoutException extends NativeDaemonConnectorException { - public NativeDaemonTimeoutException(String command, NativeDaemonEvent event) { - super(command, event); - } -} - diff --git a/packages/ConnectivityT/service/src/com/android/server/NsdService.java b/packages/ConnectivityT/service/src/com/android/server/NsdService.java deleted file mode 100644 index ddf6d2c4ab15..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NsdService.java +++ /dev/null @@ -1,1146 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.Network; -import android.net.nsd.INsdManager; -import android.net.nsd.INsdManagerCallback; -import android.net.nsd.INsdServiceConnector; -import android.net.nsd.NsdManager; -import android.net.nsd.NsdServiceInfo; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Message; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.Base64; -import android.util.Log; -import android.util.Pair; -import android.util.SparseArray; -import android.util.SparseIntArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; -import com.android.net.module.util.DnsSdTxtRecord; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; - -/** - * Network Service Discovery Service handles remote service discovery operation requests by - * implementing the INsdManager interface. - * - * @hide - */ -public class NsdService extends INsdManager.Stub { - private static final String TAG = "NsdService"; - private static final String MDNS_TAG = "mDnsConnector"; - - private static final boolean DBG = true; - private static final long CLEANUP_DELAY_MS = 10000; - private static final int IFACE_IDX_ANY = 0; - - private final Context mContext; - private final NsdStateMachine mNsdStateMachine; - private final DaemonConnection mDaemon; - private final NativeCallbackReceiver mDaemonCallback; - - /** - * Clients receiving asynchronous messages - */ - private final HashMap<NsdServiceConnector, ClientInfo> mClients = new HashMap<>(); - - /* A map from unique id to client info */ - private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>(); - - private final long mCleanupDelayMs; - - private static final int INVALID_ID = 0; - private int mUniqueId = 1; - // The count of the connected legacy clients. - private int mLegacyClientCount = 0; - - private class NsdStateMachine extends StateMachine { - - private final DefaultState mDefaultState = new DefaultState(); - private final DisabledState mDisabledState = new DisabledState(); - private final EnabledState mEnabledState = new EnabledState(); - - @Override - protected String getWhatToString(int what) { - return NsdManager.nameOf(what); - } - - private void maybeStartDaemon() { - mDaemon.maybeStart(); - maybeScheduleStop(); - } - - private boolean isAnyRequestActive() { - return mIdToClientInfoMap.size() != 0; - } - - private void scheduleStop() { - sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); - } - private void maybeScheduleStop() { - // The native daemon should stay alive and can't be cleanup - // if any legacy client connected. - if (!isAnyRequestActive() && mLegacyClientCount == 0) { - scheduleStop(); - } - } - - private void cancelStop() { - this.removeMessages(NsdManager.DAEMON_CLEANUP); - } - - NsdStateMachine(String name, Handler handler) { - super(name, handler); - addState(mDefaultState); - addState(mDisabledState, mDefaultState); - addState(mEnabledState, mDefaultState); - State initialState = mEnabledState; - setInitialState(initialState); - setLogRecSize(25); - } - - class DefaultState extends State { - @Override - public boolean processMessage(Message msg) { - final ClientInfo cInfo; - final int clientId = msg.arg2; - switch (msg.what) { - case NsdManager.REGISTER_CLIENT: - final Pair<NsdServiceConnector, INsdManagerCallback> arg = - (Pair<NsdServiceConnector, INsdManagerCallback>) msg.obj; - final INsdManagerCallback cb = arg.second; - try { - cb.asBinder().linkToDeath(arg.first, 0); - cInfo = new ClientInfo(cb); - mClients.put(arg.first, cInfo); - } catch (RemoteException e) { - Log.w(TAG, "Client " + clientId + " has already died"); - } - break; - case NsdManager.UNREGISTER_CLIENT: - final NsdServiceConnector connector = (NsdServiceConnector) msg.obj; - cInfo = mClients.remove(connector); - if (cInfo != null) { - cInfo.expungeAllRequests(); - if (cInfo.isLegacy()) { - mLegacyClientCount -= 1; - } - } - maybeScheduleStop(); - break; - case NsdManager.DISCOVER_SERVICES: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onDiscoverServicesFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.STOP_DISCOVERY: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.REGISTER_SERVICE: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.UNREGISTER_SERVICE: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onUnregisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.RESOLVE_SERVICE: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.DAEMON_CLEANUP: - mDaemon.maybeStop(); - break; - // This event should be only sent by the legacy (target SDK < S) clients. - // Mark the sending client as legacy. - case NsdManager.DAEMON_STARTUP: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cancelStop(); - cInfo.setLegacy(); - mLegacyClientCount += 1; - maybeStartDaemon(); - } - break; - case NsdManager.NATIVE_DAEMON_EVENT: - default: - Log.e(TAG, "Unhandled " + msg); - return NOT_HANDLED; - } - return HANDLED; - } - - private ClientInfo getClientInfoForReply(Message msg) { - final ListenerArgs args = (ListenerArgs) msg.obj; - return mClients.get(args.connector); - } - } - - class DisabledState extends State { - @Override - public void enter() { - sendNsdStateChangeBroadcast(false); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case NsdManager.ENABLE: - transitionTo(mEnabledState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class EnabledState extends State { - @Override - public void enter() { - sendNsdStateChangeBroadcast(true); - } - - @Override - public void exit() { - // TODO: it is incorrect to stop the daemon without expunging all requests - // and sending error callbacks to clients. - scheduleStop(); - } - - private boolean requestLimitReached(ClientInfo clientInfo) { - if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) { - if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo); - return true; - } - return false; - } - - private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) { - clientInfo.mClientIds.put(clientId, globalId); - clientInfo.mClientRequests.put(clientId, what); - mIdToClientInfoMap.put(globalId, clientInfo); - // Remove the cleanup event because here comes a new request. - cancelStop(); - } - - private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { - clientInfo.mClientIds.delete(clientId); - clientInfo.mClientRequests.delete(clientId); - mIdToClientInfoMap.remove(globalId); - maybeScheduleStop(); - } - - @Override - public boolean processMessage(Message msg) { - final ClientInfo clientInfo; - final int id; - final int clientId = msg.arg2; - final ListenerArgs args; - switch (msg.what) { - case NsdManager.DISABLE: - //TODO: cleanup clients - transitionTo(mDisabledState); - break; - case NsdManager.DISCOVER_SERVICES: - if (DBG) Log.d(TAG, "Discover services"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - - if (requestLimitReached(clientInfo)) { - clientInfo.onDiscoverServicesFailed( - clientId, NsdManager.FAILURE_MAX_LIMIT); - break; - } - - maybeStartDaemon(); - id = getUniqueId(); - if (discoverServices(id, args.serviceInfo)) { - if (DBG) { - Log.d(TAG, "Discover " + msg.arg2 + " " + id - + args.serviceInfo.getServiceType()); - } - storeRequestMap(clientId, id, clientInfo, msg.what); - clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo); - } else { - stopServiceDiscovery(id); - clientInfo.onDiscoverServicesFailed(clientId, - NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.STOP_DISCOVERY: - if (DBG) Log.d(TAG, "Stop service discovery"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - - try { - id = clientInfo.mClientIds.get(clientId); - } catch (NullPointerException e) { - clientInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - } - removeRequestMap(clientId, id, clientInfo); - if (stopServiceDiscovery(id)) { - clientInfo.onStopDiscoverySucceeded(clientId); - } else { - clientInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.REGISTER_SERVICE: - if (DBG) Log.d(TAG, "Register service"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - if (requestLimitReached(clientInfo)) { - clientInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_MAX_LIMIT); - break; - } - - maybeStartDaemon(); - id = getUniqueId(); - if (registerService(id, args.serviceInfo)) { - if (DBG) Log.d(TAG, "Register " + clientId + " " + id); - storeRequestMap(clientId, id, clientInfo, msg.what); - // Return success after mDns reports success - } else { - unregisterService(id); - clientInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.UNREGISTER_SERVICE: - if (DBG) Log.d(TAG, "unregister service"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - if (clientInfo == null) { - Log.e(TAG, "Unknown connector in unregistration"); - break; - } - id = clientInfo.mClientIds.get(clientId); - removeRequestMap(clientId, id, clientInfo); - if (unregisterService(id)) { - clientInfo.onUnregisterServiceSucceeded(clientId); - } else { - clientInfo.onUnregisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.RESOLVE_SERVICE: - if (DBG) Log.d(TAG, "Resolve service"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - - if (clientInfo.mResolvedService != null) { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_ALREADY_ACTIVE); - break; - } - - maybeStartDaemon(); - id = getUniqueId(); - if (resolveService(id, args.serviceInfo)) { - clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(clientId, id, clientInfo, msg.what); - } else { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.NATIVE_DAEMON_EVENT: - NativeEvent event = (NativeEvent) msg.obj; - if (!handleNativeEvent(event.code, event.raw, event.cooked)) { - return NOT_HANDLED; - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - private boolean handleNativeEvent(int code, String raw, String[] cooked) { - NsdServiceInfo servInfo; - int id = Integer.parseInt(cooked[1]); - ClientInfo clientInfo = mIdToClientInfoMap.get(id); - if (clientInfo == null) { - String name = NativeResponseCode.nameOf(code); - Log.e(TAG, String.format("id %d for %s has no client mapping", id, name)); - return false; - } - - /* This goes in response as msg.arg2 */ - int clientId = clientInfo.getClientId(id); - if (clientId < 0) { - // This can happen because of race conditions. For example, - // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY, - // and we may get in this situation. - String name = NativeResponseCode.nameOf(code); - Log.d(TAG, String.format( - "Notification %s for listener id %d that is no longer active", - name, id)); - return false; - } - if (DBG) { - String name = NativeResponseCode.nameOf(code); - Log.d(TAG, String.format("Native daemon message %s: %s", name, raw)); - } - switch (code) { - case NativeResponseCode.SERVICE_FOUND: - /* NNN uniqueId serviceName regType domain interfaceIdx netId */ - servInfo = new NsdServiceInfo(cooked[2], cooked[3]); - final int foundNetId; - try { - foundNetId = Integer.parseInt(cooked[6]); - } catch (NumberFormatException e) { - Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); - break; - } - if (foundNetId == 0L) { - // Ignore services that do not have a Network: they are not usable - // by apps, as they would need privileged permissions to use - // interfaces that do not have an associated Network. - break; - } - servInfo.setNetwork(new Network(foundNetId)); - clientInfo.onServiceFound(clientId, servInfo); - break; - case NativeResponseCode.SERVICE_LOST: - /* NNN uniqueId serviceName regType domain interfaceIdx netId */ - final int lostNetId; - try { - lostNetId = Integer.parseInt(cooked[6]); - } catch (NumberFormatException e) { - Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); - break; - } - servInfo = new NsdServiceInfo(cooked[2], cooked[3]); - // The network could be null if it was torn down when the service is lost - // TODO: avoid returning null in that case, possibly by remembering found - // services on the same interface index and their network at the time - servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId)); - clientInfo.onServiceLost(clientId, servInfo); - break; - case NativeResponseCode.SERVICE_DISCOVERY_FAILED: - /* NNN uniqueId errorCode */ - clientInfo.onDiscoverServicesFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_REGISTERED: - /* NNN regId serviceName regType */ - servInfo = new NsdServiceInfo(cooked[2], null); - clientInfo.onRegisterServiceSucceeded(clientId, servInfo); - break; - case NativeResponseCode.SERVICE_REGISTRATION_FAILED: - /* NNN regId errorCode */ - clientInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_UPDATED: - /* NNN regId */ - break; - case NativeResponseCode.SERVICE_UPDATE_FAILED: - /* NNN regId errorCode */ - break; - case NativeResponseCode.SERVICE_RESOLVED: - /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */ - int index = 0; - while (index < cooked[2].length() && cooked[2].charAt(index) != '.') { - if (cooked[2].charAt(index) == '\\') { - ++index; - } - ++index; - } - if (index >= cooked[2].length()) { - Log.e(TAG, "Invalid service found " + raw); - break; - } - - String name = cooked[2].substring(0, index); - String rest = cooked[2].substring(index); - String type = rest.replace(".local.", ""); - - name = unescape(name); - - clientInfo.mResolvedService.setServiceName(name); - clientInfo.mResolvedService.setServiceType(type); - clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); - clientInfo.mResolvedService.setTxtRecords(cooked[6]); - // Network will be added after SERVICE_GET_ADDR_SUCCESS - - stopResolveService(id); - removeRequestMap(clientId, id, clientInfo); - - int id2 = getUniqueId(); - if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) { - storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); - } else { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - clientInfo.mResolvedService = null; - } - break; - case NativeResponseCode.SERVICE_RESOLUTION_FAILED: - /* NNN resolveId errorCode */ - stopResolveService(id); - removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_GET_ADDR_FAILED: - /* NNN resolveId errorCode */ - stopGetAddrInfo(id); - removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: - /* NNN resolveId hostname ttl addr interfaceIdx netId */ - Network network = null; - try { - final int netId = Integer.parseInt(cooked[6]); - network = netId == 0L ? null : new Network(netId); - } catch (NumberFormatException e) { - Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e); - } - - InetAddress serviceHost = null; - try { - serviceHost = InetAddress.getByName(cooked[4]); - } catch (UnknownHostException e) { - Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e); - } - - // If the resolved service is on an interface without a network, consider it - // as a failure: it would not be usable by apps as they would need - // privileged permissions. - if (network != null && serviceHost != null) { - clientInfo.mResolvedService.setHost(serviceHost); - clientInfo.mResolvedService.setNetwork(network); - clientInfo.onResolveServiceSucceeded( - clientId, clientInfo.mResolvedService); - } else { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - stopGetAddrInfo(id); - removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; - break; - default: - return false; - } - return true; - } - } - } - - private String unescape(String s) { - StringBuilder sb = new StringBuilder(s.length()); - for (int i = 0; i < s.length(); ++i) { - char c = s.charAt(i); - if (c == '\\') { - if (++i >= s.length()) { - Log.e(TAG, "Unexpected end of escape sequence in: " + s); - break; - } - c = s.charAt(i); - if (c != '.' && c != '\\') { - if (i + 2 >= s.length()) { - Log.e(TAG, "Unexpected end of escape sequence in: " + s); - break; - } - c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0')); - i += 2; - } - } - sb.append(c); - } - return sb.toString(); - } - - @VisibleForTesting - NsdService(Context ctx, Handler handler, DaemonConnectionSupplier fn, long cleanupDelayMs) { - mCleanupDelayMs = cleanupDelayMs; - mContext = ctx; - mNsdStateMachine = new NsdStateMachine(TAG, handler); - mNsdStateMachine.start(); - mDaemonCallback = new NativeCallbackReceiver(); - mDaemon = fn.get(mDaemonCallback); - } - - public static NsdService create(Context context) throws InterruptedException { - HandlerThread thread = new HandlerThread(TAG); - thread.start(); - Handler handler = new Handler(thread.getLooper()); - NsdService service = - new NsdService(context, handler, DaemonConnection::new, CLEANUP_DELAY_MS); - service.mDaemonCallback.awaitConnection(); - return service; - } - - @Override - public INsdServiceConnector connect(INsdManagerCallback cb) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService"); - final INsdServiceConnector connector = new NsdServiceConnector(); - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.REGISTER_CLIENT, new Pair<>(connector, cb))); - return connector; - } - - private static class ListenerArgs { - public final NsdServiceConnector connector; - public final NsdServiceInfo serviceInfo; - ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) { - this.connector = connector; - this.serviceInfo = serviceInfo; - } - } - - private class NsdServiceConnector extends INsdServiceConnector.Stub - implements IBinder.DeathRecipient { - @Override - public void registerService(int listenerKey, NsdServiceInfo serviceInfo) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.REGISTER_SERVICE, 0, listenerKey, - new ListenerArgs(this, serviceInfo))); - } - - @Override - public void unregisterService(int listenerKey) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.UNREGISTER_SERVICE, 0, listenerKey, - new ListenerArgs(this, null))); - } - - @Override - public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.DISCOVER_SERVICES, 0, listenerKey, - new ListenerArgs(this, serviceInfo))); - } - - @Override - public void stopDiscovery(int listenerKey) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.STOP_DISCOVERY, 0, listenerKey, new ListenerArgs(this, null))); - } - - @Override - public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.RESOLVE_SERVICE, 0, listenerKey, - new ListenerArgs(this, serviceInfo))); - } - - @Override - public void startDaemon() { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null))); - } - - @Override - public void binderDied() { - mNsdStateMachine.sendMessage( - mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this)); - } - } - - private void sendNsdStateChangeBroadcast(boolean isEnabled) { - final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED; - intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private int getUniqueId() { - if (++mUniqueId == INVALID_ID) return ++mUniqueId; - return mUniqueId; - } - - /* These should be in sync with system/netd/server/ResponseCode.h */ - static final class NativeResponseCode { - public static final int SERVICE_DISCOVERY_FAILED = 602; - public static final int SERVICE_FOUND = 603; - public static final int SERVICE_LOST = 604; - - public static final int SERVICE_REGISTRATION_FAILED = 605; - public static final int SERVICE_REGISTERED = 606; - - public static final int SERVICE_RESOLUTION_FAILED = 607; - public static final int SERVICE_RESOLVED = 608; - - public static final int SERVICE_UPDATED = 609; - public static final int SERVICE_UPDATE_FAILED = 610; - - public static final int SERVICE_GET_ADDR_FAILED = 611; - public static final int SERVICE_GET_ADDR_SUCCESS = 612; - - private static final SparseArray<String> CODE_NAMES = new SparseArray<>(); - static { - CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED"); - CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND"); - CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST"); - CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED"); - CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED"); - CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED"); - CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED"); - CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED"); - CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED"); - CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED"); - CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS"); - } - - static String nameOf(int code) { - String name = CODE_NAMES.get(code); - if (name == null) { - return Integer.toString(code); - } - return name; - } - } - - private class NativeEvent { - final int code; - final String raw; - final String[] cooked; - - NativeEvent(int code, String raw, String[] cooked) { - this.code = code; - this.raw = raw; - this.cooked = cooked; - } - } - - class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks { - private final CountDownLatch connected = new CountDownLatch(1); - - public void awaitConnection() throws InterruptedException { - connected.await(); - } - - @Override - public void onDaemonConnected() { - connected.countDown(); - } - - @Override - public boolean onCheckHoldWakeLock(int code) { - return false; - } - - @Override - public boolean onEvent(int code, String raw, String[] cooked) { - // TODO: NDC translates a message to a callback, we could enhance NDC to - // directly interact with a state machine through messages - NativeEvent event = new NativeEvent(code, raw, cooked); - mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event); - return true; - } - } - - interface DaemonConnectionSupplier { - DaemonConnection get(NativeCallbackReceiver callback); - } - - @VisibleForTesting - public static class DaemonConnection { - final NativeDaemonConnector mNativeConnector; - boolean mIsStarted = false; - - DaemonConnection(NativeCallbackReceiver callback) { - mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null); - new Thread(mNativeConnector, MDNS_TAG).start(); - } - - /** - * Executes the specified cmd on the daemon. - */ - public boolean execute(Object... args) { - if (DBG) { - Log.d(TAG, "mdnssd " + Arrays.toString(args)); - } - try { - mNativeConnector.execute("mdnssd", args); - } catch (NativeDaemonConnectorException e) { - Log.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e); - return false; - } - return true; - } - - /** - * Starts the daemon if it is not already started. - */ - public void maybeStart() { - if (mIsStarted) { - return; - } - execute("start-service"); - mIsStarted = true; - } - - /** - * Stops the daemon if it is started. - */ - public void maybeStop() { - if (!mIsStarted) { - return; - } - execute("stop-service"); - mIsStarted = false; - } - } - - private boolean registerService(int regId, NsdServiceInfo service) { - if (DBG) { - Log.d(TAG, "registerService: " + regId + " " + service); - } - String name = service.getServiceName(); - String type = service.getServiceType(); - int port = service.getPort(); - byte[] textRecord = service.getTxtRecord(); - String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", ""); - return mDaemon.execute("register", regId, name, type, port, record); - } - - private boolean unregisterService(int regId) { - return mDaemon.execute("stop-register", regId); - } - - private boolean updateService(int regId, DnsSdTxtRecord t) { - if (t == null) { - return false; - } - return mDaemon.execute("update", regId, t.size(), t.getRawData()); - } - - private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) { - final Network network = serviceInfo.getNetwork(); - final int discoverInterface = getNetworkInterfaceIndex(network); - if (network != null && discoverInterface == IFACE_IDX_ANY) { - Log.e(TAG, "Interface to discover service on not found"); - return false; - } - return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(), - discoverInterface); - } - - private boolean stopServiceDiscovery(int discoveryId) { - return mDaemon.execute("stop-discover", discoveryId); - } - - private boolean resolveService(int resolveId, NsdServiceInfo service) { - final String name = service.getServiceName(); - final String type = service.getServiceType(); - final Network network = service.getNetwork(); - final int resolveInterface = getNetworkInterfaceIndex(network); - if (network != null && resolveInterface == IFACE_IDX_ANY) { - Log.e(TAG, "Interface to resolve service on not found"); - return false; - } - return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface); - } - - /** - * Guess the interface to use to resolve or discover a service on a specific network. - * - * This is an imperfect guess, as for example the network may be gone or not yet fully - * registered. This is fine as failing is correct if the network is gone, and a client - * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also - * this is to support the legacy mdnsresponder implementation, which historically resolved - * services on an unspecified network. - */ - private int getNetworkInterfaceIndex(Network network) { - if (network == null) return IFACE_IDX_ANY; - - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - if (cm == null) { - Log.wtf(TAG, "No ConnectivityManager for resolveService"); - return IFACE_IDX_ANY; - } - final LinkProperties lp = cm.getLinkProperties(network); - if (lp == null) return IFACE_IDX_ANY; - - // Only resolve on non-stacked interfaces - final NetworkInterface iface; - try { - iface = NetworkInterface.getByName(lp.getInterfaceName()); - } catch (SocketException e) { - Log.e(TAG, "Error querying interface", e); - return IFACE_IDX_ANY; - } - - if (iface == null) { - Log.e(TAG, "Interface not found: " + lp.getInterfaceName()); - return IFACE_IDX_ANY; - } - - return iface.getIndex(); - } - - private boolean stopResolveService(int resolveId) { - return mDaemon.execute("stop-resolve", resolveId); - } - - private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) { - // interfaceIdx is always obtained (as string) from the service resolved callback - return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx); - } - - private boolean stopGetAddrInfo(int resolveId) { - return mDaemon.execute("stop-getaddrinfo", resolveId); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump " + TAG - + " due to missing android.permission.DUMP permission"); - return; - } - - for (ClientInfo client : mClients.values()) { - pw.println("Client Info"); - pw.println(client); - } - - mNsdStateMachine.dump(fd, pw, args); - } - - /* Information tracked per client */ - private class ClientInfo { - - private static final int MAX_LIMIT = 10; - private final INsdManagerCallback mCb; - /* Remembers a resolved service until getaddrinfo completes */ - private NsdServiceInfo mResolvedService; - - /* A map from client id to unique id sent to mDns */ - private final SparseIntArray mClientIds = new SparseIntArray(); - - /* A map from client id to the type of the request we had received */ - private final SparseIntArray mClientRequests = new SparseIntArray(); - - // The target SDK of this client < Build.VERSION_CODES.S - private boolean mIsLegacy = false; - - private ClientInfo(INsdManagerCallback cb) { - mCb = cb; - if (DBG) Log.d(TAG, "New client"); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("mResolvedService ").append(mResolvedService).append("\n"); - sb.append("mIsLegacy ").append(mIsLegacy).append("\n"); - for(int i = 0; i< mClientIds.size(); i++) { - int clientID = mClientIds.keyAt(i); - sb.append("clientId ").append(clientID). - append(" mDnsId ").append(mClientIds.valueAt(i)). - append(" type ").append(mClientRequests.get(clientID)).append("\n"); - } - return sb.toString(); - } - - private boolean isLegacy() { - return mIsLegacy; - } - - private void setLegacy() { - mIsLegacy = true; - } - - // Remove any pending requests from the global map when we get rid of a client, - // and send cancellations to the daemon. - private void expungeAllRequests() { - int globalId, clientId, i; - // TODO: to keep handler responsive, do not clean all requests for that client at once. - for (i = 0; i < mClientIds.size(); i++) { - clientId = mClientIds.keyAt(i); - globalId = mClientIds.valueAt(i); - mIdToClientInfoMap.remove(globalId); - if (DBG) { - Log.d(TAG, "Terminating client-ID " + clientId - + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); - } - switch (mClientRequests.get(clientId)) { - case NsdManager.DISCOVER_SERVICES: - stopServiceDiscovery(globalId); - break; - case NsdManager.RESOLVE_SERVICE: - stopResolveService(globalId); - break; - case NsdManager.REGISTER_SERVICE: - unregisterService(globalId); - break; - default: - break; - } - } - mClientIds.clear(); - mClientRequests.clear(); - } - - // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, - // return the corresponding listener id. mDnsClient id is also called a global id. - private int getClientId(final int globalId) { - int idx = mClientIds.indexOfValue(globalId); - if (idx < 0) { - return idx; - } - return mClientIds.keyAt(idx); - } - - void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) { - try { - mCb.onDiscoverServicesStarted(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onDiscoverServicesStarted", e); - } - } - - void onDiscoverServicesFailed(int listenerKey, int error) { - try { - mCb.onDiscoverServicesFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onDiscoverServicesFailed", e); - } - } - - void onServiceFound(int listenerKey, NsdServiceInfo info) { - try { - mCb.onServiceFound(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onServiceFound(", e); - } - } - - void onServiceLost(int listenerKey, NsdServiceInfo info) { - try { - mCb.onServiceLost(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onServiceLost(", e); - } - } - - void onStopDiscoveryFailed(int listenerKey, int error) { - try { - mCb.onStopDiscoveryFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onStopDiscoveryFailed", e); - } - } - - void onStopDiscoverySucceeded(int listenerKey) { - try { - mCb.onStopDiscoverySucceeded(listenerKey); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onStopDiscoverySucceeded", e); - } - } - - void onRegisterServiceFailed(int listenerKey, int error) { - try { - mCb.onRegisterServiceFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onRegisterServiceFailed", e); - } - } - - void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) { - try { - mCb.onRegisterServiceSucceeded(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onRegisterServiceSucceeded", e); - } - } - - void onUnregisterServiceFailed(int listenerKey, int error) { - try { - mCb.onUnregisterServiceFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onUnregisterServiceFailed", e); - } - } - - void onUnregisterServiceSucceeded(int listenerKey) { - try { - mCb.onUnregisterServiceSucceeded(listenerKey); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e); - } - } - - void onResolveServiceFailed(int listenerKey, int error) { - try { - mCb.onResolveServiceFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onResolveServiceFailed", e); - } - } - - void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) { - try { - mCb.onResolveServiceSucceeded(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onResolveServiceSucceeded", e); - } - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java b/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java deleted file mode 100644 index 25c88eb6bdb2..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.net; - -import android.content.Context; -import android.net.INetd; -import android.os.Handler; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.ErrnoException; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.BaseNetdUnsolicitedEventListener; -import com.android.net.module.util.BpfMap; -import com.android.net.module.util.IBpfMap; -import com.android.net.module.util.InterfaceParams; -import com.android.net.module.util.Struct.U32; - -/** - * Monitor interface added (without removed) and right interface name and its index to bpf map. - */ -public class BpfInterfaceMapUpdater { - private static final String TAG = BpfInterfaceMapUpdater.class.getSimpleName(); - // This is current path but may be changed soon. - private static final String IFACE_INDEX_NAME_MAP_PATH = - "/sys/fs/bpf/map_netd_iface_index_name_map"; - private final IBpfMap<U32, InterfaceMapValue> mBpfMap; - private final INetd mNetd; - private final Handler mHandler; - private final Dependencies mDeps; - - public BpfInterfaceMapUpdater(Context ctx, Handler handler) { - this(ctx, handler, new Dependencies()); - } - - @VisibleForTesting - public BpfInterfaceMapUpdater(Context ctx, Handler handler, Dependencies deps) { - mDeps = deps; - mBpfMap = deps.getInterfaceMap(); - mNetd = deps.getINetd(ctx); - mHandler = handler; - } - - /** - * Dependencies of BpfInerfaceMapUpdater, for injection in tests. - */ - @VisibleForTesting - public static class Dependencies { - /** Create BpfMap for updating interface and index mapping. */ - public IBpfMap<U32, InterfaceMapValue> getInterfaceMap() { - try { - return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH, BpfMap.BPF_F_RDWR, - U32.class, InterfaceMapValue.class); - } catch (ErrnoException e) { - Log.e(TAG, "Cannot create interface map: " + e); - return null; - } - } - - /** Get InterfaceParams for giving interface name. */ - public InterfaceParams getInterfaceParams(String ifaceName) { - return InterfaceParams.getByName(ifaceName); - } - - /** Get INetd binder object. */ - public INetd getINetd(Context ctx) { - return INetd.Stub.asInterface((IBinder) ctx.getSystemService(Context.NETD_SERVICE)); - } - } - - /** - * Start listening interface update event. - * Query current interface names before listening. - */ - public void start() { - mHandler.post(() -> { - if (mBpfMap == null) { - Log.wtf(TAG, "Fail to start: Null bpf map"); - return; - } - - try { - // TODO: use a NetlinkMonitor and listen for RTM_NEWLINK messages instead. - mNetd.registerUnsolicitedEventListener(new InterfaceChangeObserver()); - } catch (RemoteException e) { - Log.wtf(TAG, "Unable to register netd UnsolicitedEventListener, " + e); - } - - final String[] ifaces; - try { - // TODO: use a netlink dump to get the current interface list. - ifaces = mNetd.interfaceGetList(); - } catch (RemoteException | ServiceSpecificException e) { - Log.wtf(TAG, "Unable to query interface names by netd, " + e); - return; - } - - for (String ifaceName : ifaces) { - addInterface(ifaceName); - } - }); - } - - private void addInterface(String ifaceName) { - final InterfaceParams iface = mDeps.getInterfaceParams(ifaceName); - if (iface == null) { - Log.e(TAG, "Unable to get InterfaceParams for " + ifaceName); - return; - } - - try { - mBpfMap.updateEntry(new U32(iface.index), new InterfaceMapValue(ifaceName)); - } catch (ErrnoException e) { - Log.e(TAG, "Unable to update entry for " + ifaceName + ", " + e); - } - } - - private class InterfaceChangeObserver extends BaseNetdUnsolicitedEventListener { - @Override - public void onInterfaceAdded(String ifName) { - mHandler.post(() -> addInterface(ifName)); - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java deleted file mode 100644 index 443e5b38475e..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Key for cookie tag map. - */ -public class CookieTagMapKey extends Struct { - @Field(order = 0, type = Type.S64) - public final long socketCookie; - - public CookieTagMapKey(final long socketCookie) { - this.socketCookie = socketCookie; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java deleted file mode 100644 index 93b9195f92da..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Value for cookie tag map. - */ -public class CookieTagMapValue extends Struct { - @Field(order = 0, type = Type.U32) - public final long uid; - - @Field(order = 1, type = Type.U32) - public final long tag; - - public CookieTagMapValue(final long uid, final long tag) { - this.uid = uid; - this.tag = tag; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java b/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java deleted file mode 100644 index 35dc4557252c..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import android.os.Handler; -import android.os.HandlerThread; -import android.text.TextUtils; -import android.util.Log; - -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * This class provides APIs to do a delayed data write to a given {@link OutputStream}. - */ -public class DelayedDiskWrite { - private static final String TAG = "DelayedDiskWrite"; - - private HandlerThread mDiskWriteHandlerThread; - private Handler mDiskWriteHandler; - /* Tracks multiple writes on the same thread */ - private int mWriteSequence = 0; - - /** - * Used to do a delayed data write to a given {@link OutputStream}. - */ - public interface Writer { - /** - * write data to a given {@link OutputStream}. - */ - void onWriteCalled(DataOutputStream out) throws IOException; - } - - /** - * Do a delayed data write to a given output stream opened from filePath. - */ - public void write(final String filePath, final Writer w) { - write(filePath, w, true); - } - - /** - * Do a delayed data write to a given output stream opened from filePath. - */ - public void write(final String filePath, final Writer w, final boolean open) { - if (TextUtils.isEmpty(filePath)) { - throw new IllegalArgumentException("empty file path"); - } - - /* Do a delayed write to disk on a separate handler thread */ - synchronized (this) { - if (++mWriteSequence == 1) { - mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread"); - mDiskWriteHandlerThread.start(); - mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper()); - } - } - - mDiskWriteHandler.post(new Runnable() { - @Override - public void run() { - doWrite(filePath, w, open); - } - }); - } - - private void doWrite(String filePath, Writer w, boolean open) { - DataOutputStream out = null; - try { - if (open) { - out = new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(filePath))); - } - w.onWriteCalled(out); - } catch (IOException e) { - loge("Error writing data file " + filePath); - } finally { - if (out != null) { - try { - out.close(); - } catch (Exception e) { } - } - - // Quit if no more writes sent - synchronized (this) { - if (--mWriteSequence == 0) { - mDiskWriteHandler.getLooper().quit(); - mDiskWriteHandler = null; - mDiskWriteHandlerThread = null; - } - } - } - } - - private void loge(String s) { - Log.e(TAG, s); - } -} - diff --git a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java deleted file mode 100644 index 42c0044e666f..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.net; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * The value of bpf interface index map which is used for NetworkStatsService. - */ -public class InterfaceMapValue extends Struct { - @Field(order = 0, type = Type.ByteArray, arraysize = 16) - public final byte[] interfaceName; - - public InterfaceMapValue(String iface) { - final byte[] ifaceArray = iface.getBytes(); - interfaceName = new byte[16]; - // All array bytes after the interface name, if any, must be 0. - System.arraycopy(ifaceArray, 0, interfaceName, 0, ifaceArray.length); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java b/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java deleted file mode 100644 index 3a9a54415537..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import android.net.InetAddresses; -import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; -import android.net.LinkAddress; -import android.net.ProxyInfo; -import android.net.StaticIpConfiguration; -import android.net.Uri; -import android.util.ArrayMap; -import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.ProxyUtils; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; - -/** - * This class provides an API to store and manage L3 network IP configuration. - */ -public class IpConfigStore { - private static final String TAG = "IpConfigStore"; - private static final boolean DBG = false; - - protected final DelayedDiskWrite mWriter; - - /* IP and proxy configuration keys */ - protected static final String ID_KEY = "id"; - protected static final String IP_ASSIGNMENT_KEY = "ipAssignment"; - protected static final String LINK_ADDRESS_KEY = "linkAddress"; - protected static final String GATEWAY_KEY = "gateway"; - protected static final String DNS_KEY = "dns"; - protected static final String PROXY_SETTINGS_KEY = "proxySettings"; - protected static final String PROXY_HOST_KEY = "proxyHost"; - protected static final String PROXY_PORT_KEY = "proxyPort"; - protected static final String PROXY_PAC_FILE = "proxyPac"; - protected static final String EXCLUSION_LIST_KEY = "exclusionList"; - protected static final String EOS = "eos"; - - protected static final int IPCONFIG_FILE_VERSION = 3; - - public IpConfigStore(DelayedDiskWrite writer) { - mWriter = writer; - } - - public IpConfigStore() { - this(new DelayedDiskWrite()); - } - - private static boolean writeConfig(DataOutputStream out, String configKey, - IpConfiguration config) throws IOException { - return writeConfig(out, configKey, config, IPCONFIG_FILE_VERSION); - } - - /** - * Write the IP configuration with the given parameters to {@link DataOutputStream}. - */ - @VisibleForTesting - public static boolean writeConfig(DataOutputStream out, String configKey, - IpConfiguration config, int version) throws IOException { - boolean written = false; - - try { - switch (config.getIpAssignment()) { - case STATIC: - out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.getIpAssignment().toString()); - StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration(); - if (staticIpConfiguration != null) { - if (staticIpConfiguration.getIpAddress() != null) { - LinkAddress ipAddress = staticIpConfiguration.getIpAddress(); - out.writeUTF(LINK_ADDRESS_KEY); - out.writeUTF(ipAddress.getAddress().getHostAddress()); - out.writeInt(ipAddress.getPrefixLength()); - } - if (staticIpConfiguration.getGateway() != null) { - out.writeUTF(GATEWAY_KEY); - out.writeInt(0); // Default route. - out.writeInt(1); // Have a gateway. - out.writeUTF(staticIpConfiguration.getGateway().getHostAddress()); - } - for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) { - out.writeUTF(DNS_KEY); - out.writeUTF(inetAddr.getHostAddress()); - } - } - written = true; - break; - case DHCP: - out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.getIpAssignment().toString()); - written = true; - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignore invalid ip assignment while writing"); - break; - } - - switch (config.getProxySettings()) { - case STATIC: - ProxyInfo proxyProperties = config.getHttpProxy(); - String exclusionList = ProxyUtils.exclusionListAsString( - proxyProperties.getExclusionList()); - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.getProxySettings().toString()); - out.writeUTF(PROXY_HOST_KEY); - out.writeUTF(proxyProperties.getHost()); - out.writeUTF(PROXY_PORT_KEY); - out.writeInt(proxyProperties.getPort()); - if (exclusionList != null) { - out.writeUTF(EXCLUSION_LIST_KEY); - out.writeUTF(exclusionList); - } - written = true; - break; - case PAC: - ProxyInfo proxyPacProperties = config.getHttpProxy(); - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.getProxySettings().toString()); - out.writeUTF(PROXY_PAC_FILE); - out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); - written = true; - break; - case NONE: - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.getProxySettings().toString()); - written = true; - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignore invalid proxy settings while writing"); - break; - } - - if (written) { - out.writeUTF(ID_KEY); - if (version < 3) { - out.writeInt(Integer.valueOf(configKey)); - } else { - out.writeUTF(configKey); - } - } - } catch (NullPointerException e) { - loge("Failure in writing " + config + e); - } - out.writeUTF(EOS); - - return written; - } - - /** - * @deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. - * New method uses string as network identifier which could be interface name or MAC address or - * other token. - */ - @Deprecated - public void writeIpAndProxyConfigurationsToFile(String filePath, - final SparseArray<IpConfiguration> networks) { - mWriter.write(filePath, out -> { - out.writeInt(IPCONFIG_FILE_VERSION); - for (int i = 0; i < networks.size(); i++) { - writeConfig(out, String.valueOf(networks.keyAt(i)), networks.valueAt(i)); - } - }); - } - - /** - * Write the IP configuration associated to the target networks to the destination path. - */ - public void writeIpConfigurations(String filePath, - ArrayMap<String, IpConfiguration> networks) { - mWriter.write(filePath, out -> { - out.writeInt(IPCONFIG_FILE_VERSION); - for (int i = 0; i < networks.size(); i++) { - writeConfig(out, networks.keyAt(i), networks.valueAt(i)); - } - }); - } - - /** - * Read the IP configuration from the destination path to {@link BufferedInputStream}. - */ - public static ArrayMap<String, IpConfiguration> readIpConfigurations(String filePath) { - BufferedInputStream bufferedInputStream; - try { - bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); - } catch (FileNotFoundException e) { - // Return an empty array here because callers expect an empty array when the file is - // not present. - loge("Error opening configuration file: " + e); - return new ArrayMap<>(0); - } - return readIpConfigurations(bufferedInputStream); - } - - /** @deprecated use {@link #readIpConfigurations(String)} */ - @Deprecated - public static SparseArray<IpConfiguration> readIpAndProxyConfigurations(String filePath) { - BufferedInputStream bufferedInputStream; - try { - bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); - } catch (FileNotFoundException e) { - // Return an empty array here because callers expect an empty array when the file is - // not present. - loge("Error opening configuration file: " + e); - return new SparseArray<>(); - } - return readIpAndProxyConfigurations(bufferedInputStream); - } - - /** @deprecated use {@link #readIpConfigurations(InputStream)} */ - @Deprecated - public static SparseArray<IpConfiguration> readIpAndProxyConfigurations( - InputStream inputStream) { - ArrayMap<String, IpConfiguration> networks = readIpConfigurations(inputStream); - if (networks == null) { - return null; - } - - SparseArray<IpConfiguration> networksById = new SparseArray<>(); - for (int i = 0; i < networks.size(); i++) { - int id = Integer.valueOf(networks.keyAt(i)); - networksById.put(id, networks.valueAt(i)); - } - - return networksById; - } - - /** Returns a map of network identity token and {@link IpConfiguration}. */ - public static ArrayMap<String, IpConfiguration> readIpConfigurations( - InputStream inputStream) { - ArrayMap<String, IpConfiguration> networks = new ArrayMap<>(); - DataInputStream in = null; - try { - in = new DataInputStream(inputStream); - - int version = in.readInt(); - if (version != 3 && version != 2 && version != 1) { - loge("Bad version on IP configuration file, ignore read"); - return null; - } - - while (true) { - String uniqueToken = null; - // Default is DHCP with no proxy - IpAssignment ipAssignment = IpAssignment.DHCP; - ProxySettings proxySettings = ProxySettings.NONE; - StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); - LinkAddress linkAddress = null; - InetAddress gatewayAddress = null; - String proxyHost = null; - String pacFileUrl = null; - int proxyPort = -1; - String exclusionList = null; - String key; - final List<InetAddress> dnsServers = new ArrayList<>(); - - do { - key = in.readUTF(); - try { - if (key.equals(ID_KEY)) { - if (version < 3) { - int id = in.readInt(); - uniqueToken = String.valueOf(id); - } else { - uniqueToken = in.readUTF(); - } - } else if (key.equals(IP_ASSIGNMENT_KEY)) { - ipAssignment = IpAssignment.valueOf(in.readUTF()); - } else if (key.equals(LINK_ADDRESS_KEY)) { - LinkAddress parsedLinkAddress = - new LinkAddress( - InetAddresses.parseNumericAddress(in.readUTF()), - in.readInt()); - if (parsedLinkAddress.getAddress() instanceof Inet4Address - && linkAddress == null) { - linkAddress = parsedLinkAddress; - } else { - loge("Non-IPv4 or duplicate address: " + parsedLinkAddress); - } - } else if (key.equals(GATEWAY_KEY)) { - LinkAddress dest = null; - InetAddress gateway = null; - if (version == 1) { - // only supported default gateways - leave the dest/prefix empty - gateway = InetAddresses.parseNumericAddress(in.readUTF()); - if (gatewayAddress == null) { - gatewayAddress = gateway; - } else { - loge("Duplicate gateway: " + gateway.getHostAddress()); - } - } else { - if (in.readInt() == 1) { - dest = - new LinkAddress( - InetAddresses.parseNumericAddress(in.readUTF()), - in.readInt()); - } - if (in.readInt() == 1) { - gateway = InetAddresses.parseNumericAddress(in.readUTF()); - } - // If the destination is a default IPv4 route, use the gateway - // address unless already set. If there is no destination, assume - // it is default route and use the gateway address in all cases. - if (dest == null) { - gatewayAddress = gateway; - } else if (dest.getAddress() instanceof Inet4Address - && dest.getPrefixLength() == 0 && gatewayAddress == null) { - gatewayAddress = gateway; - } else { - loge("Non-IPv4 default or duplicate route: " - + dest.getAddress()); - } - } - } else if (key.equals(DNS_KEY)) { - dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF())); - } else if (key.equals(PROXY_SETTINGS_KEY)) { - proxySettings = ProxySettings.valueOf(in.readUTF()); - } else if (key.equals(PROXY_HOST_KEY)) { - proxyHost = in.readUTF(); - } else if (key.equals(PROXY_PORT_KEY)) { - proxyPort = in.readInt(); - } else if (key.equals(PROXY_PAC_FILE)) { - pacFileUrl = in.readUTF(); - } else if (key.equals(EXCLUSION_LIST_KEY)) { - exclusionList = in.readUTF(); - } else if (key.equals(EOS)) { - break; - } else { - loge("Ignore unknown key " + key + "while reading"); - } - } catch (IllegalArgumentException e) { - loge("Ignore invalid address while reading" + e); - } - } while (true); - - staticIpConfiguration = new StaticIpConfiguration.Builder() - .setIpAddress(linkAddress) - .setGateway(gatewayAddress) - .setDnsServers(dnsServers) - .build(); - - if (uniqueToken != null) { - IpConfiguration config = new IpConfiguration(); - networks.put(uniqueToken, config); - - switch (ipAssignment) { - case STATIC: - config.setStaticIpConfiguration(staticIpConfiguration); - config.setIpAssignment(ipAssignment); - break; - case DHCP: - config.setIpAssignment(ipAssignment); - break; - case UNASSIGNED: - loge("BUG: Found UNASSIGNED IP on file, use DHCP"); - config.setIpAssignment(IpAssignment.DHCP); - break; - default: - loge("Ignore invalid ip assignment while reading."); - config.setIpAssignment(IpAssignment.UNASSIGNED); - break; - } - - switch (proxySettings) { - case STATIC: - ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort, - ProxyUtils.exclusionStringAsList(exclusionList)); - config.setProxySettings(proxySettings); - config.setHttpProxy(proxyInfo); - break; - case PAC: - ProxyInfo proxyPacProperties = - ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); - config.setProxySettings(proxySettings); - config.setHttpProxy(proxyPacProperties); - break; - case NONE: - config.setProxySettings(proxySettings); - break; - case UNASSIGNED: - loge("BUG: Found UNASSIGNED proxy on file, use NONE"); - config.setProxySettings(ProxySettings.NONE); - break; - default: - loge("Ignore invalid proxy settings while reading"); - config.setProxySettings(ProxySettings.UNASSIGNED); - break; - } - } else { - if (DBG) log("Missing id while parsing configuration"); - } - } - } catch (EOFException ignore) { - } catch (IOException e) { - loge("Error parsing configuration: " + e); - } finally { - if (in != null) { - try { - in.close(); - } catch (Exception e) { } - } - } - - return networks; - } - - protected static void loge(String s) { - Log.e(TAG, s); - } - - protected static void log(String s) { - Log.d(TAG, s); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java deleted file mode 100644 index 3b93f1a1905f..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static android.net.NetworkStats.INTERFACES_ALL; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.TAG_ALL; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.net.NetworkStats; -import android.net.UnderlyingNetworkInfo; -import android.os.ServiceSpecificException; -import android.os.StrictMode; -import android.os.SystemClock; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ProcFileReader; -import com.android.net.module.util.CollectionUtils; -import com.android.server.BpfNetMaps; - -import libcore.io.IoUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.ProtocolException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Creates {@link NetworkStats} instances by parsing various {@code /proc/} - * files as needed. - * - * @hide - */ -public class NetworkStatsFactory { - static { - System.loadLibrary("service-connectivity"); - } - - private static final String TAG = "NetworkStatsFactory"; - - private static final boolean USE_NATIVE_PARSING = true; - private static final boolean VALIDATE_NATIVE_STATS = false; - - /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ - private final File mStatsXtIfaceAll; - /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ - private final File mStatsXtIfaceFmt; - /** Path to {@code /proc/net/xt_qtaguid/stats}. */ - private final File mStatsXtUid; - - private final boolean mUseBpfStats; - - private final Context mContext; - - private final BpfNetMaps mBpfNetMaps; - - /** - * Guards persistent data access in this class - * - * <p>In order to prevent deadlocks, critical sections protected by this lock SHALL NOT call out - * to other code that will acquire other locks within the system server. See b/134244752. - */ - private final Object mPersistentDataLock = new Object(); - - /** Set containing info about active VPNs and their underlying networks. */ - private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0]; - - // A persistent snapshot of cumulative stats since device start - @GuardedBy("mPersistentDataLock") - private NetworkStats mPersistSnapshot; - - // The persistent snapshot of tun and 464xlat adjusted stats since device start - @GuardedBy("mPersistentDataLock") - private NetworkStats mTunAnd464xlatAdjustedStats; - - /** - * (Stacked interface) -> (base interface) association for all connected ifaces since boot. - * - * Because counters must never roll backwards, once a given interface is stacked on top of an - * underlying interface, the stacked interface can never be stacked on top of - * another interface. */ - private final ConcurrentHashMap<String, String> mStackedIfaces - = new ConcurrentHashMap<>(); - - /** Informs the factory of a new stacked interface. */ - public void noteStackedIface(String stackedIface, String baseIface) { - if (stackedIface != null && baseIface != null) { - mStackedIfaces.put(stackedIface, baseIface); - } - } - - /** - * Set active VPN information for data usage migration purposes - * - * <p>Traffic on TUN-based VPNs inherently all appear to be originated from the VPN providing - * app's UID. This method is used to support migration of VPN data usage, ensuring data is - * accurately billed to the real owner of the traffic. - * - * @param vpnArray The snapshot of the currently-running VPNs. - */ - public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) { - mUnderlyingNetworkInfos = vpnArray.clone(); - } - - /** - * Get a set of interfaces containing specified ifaces and stacked interfaces. - * - * <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces - * on which the specified ones are stacked. Stacked interfaces are those noted with - * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method - * is called are guaranteed to be included. - */ - public String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) { - if (requiredIfaces == NetworkStats.INTERFACES_ALL) { - return null; - } - - HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces)); - // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse - // elements as they existed upon construction exactly once, and may - // (but are not guaranteed to) reflect any modifications subsequent to construction". - // This is enough here. - for (Map.Entry<String, String> entry : mStackedIfaces.entrySet()) { - if (relatedIfaces.contains(entry.getKey())) { - relatedIfaces.add(entry.getValue()); - } else if (relatedIfaces.contains(entry.getValue())) { - relatedIfaces.add(entry.getKey()); - } - } - - String[] outArray = new String[relatedIfaces.size()]; - return relatedIfaces.toArray(outArray); - } - - /** - * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) - */ - public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); - } - - public NetworkStatsFactory(@NonNull Context ctx) { - this(ctx, new File("/proc/"), true); - } - - @VisibleForTesting - public NetworkStatsFactory(@NonNull Context ctx, File procRoot, boolean useBpfStats) { - mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); - mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); - mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); - mUseBpfStats = useBpfStats; - mBpfNetMaps = new BpfNetMaps(); - synchronized (mPersistentDataLock) { - mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); - mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); - } - mContext = ctx; - } - - public NetworkStats readBpfNetworkStatsDev() throws IOException { - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - if (nativeReadNetworkStatsDev(stats) != 0) { - throw new IOException("Failed to parse bpf iface stats"); - } - return stats; - } - - /** - * Parse and return interface-level summary {@link NetworkStats} measured - * using {@code /proc/net/dev} style hooks, which may include non IP layer - * traffic. Values monotonically increase since device boot, and may include - * details about inactive interfaces. - * - * @throws IllegalStateException when problem parsing stats. - */ - public NetworkStats readNetworkStatsSummaryDev() throws IOException { - - // Return xt_bpf stats if switched to bpf module. - if (mUseBpfStats) - return readBpfNetworkStatsDev(); - - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - ProcFileReader reader = null; - try { - reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceAll)); - - while (reader.hasMoreData()) { - entry.iface = reader.nextString(); - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - - final boolean active = reader.nextInt() != 0; - - // always include snapshot values - entry.rxBytes = reader.nextLong(); - entry.rxPackets = reader.nextLong(); - entry.txBytes = reader.nextLong(); - entry.txPackets = reader.nextLong(); - - // fold in active numbers, but only when active - if (active) { - entry.rxBytes += reader.nextLong(); - entry.rxPackets += reader.nextLong(); - entry.txBytes += reader.nextLong(); - entry.txPackets += reader.nextLong(); - } - - stats.insertEntry(entry); - reader.finishLine(); - } - } catch (NullPointerException|NumberFormatException e) { - throw protocolExceptionWithCause("problem parsing stats", e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - return stats; - } - - /** - * Parse and return interface-level summary {@link NetworkStats}. Designed - * to return only IP layer traffic. Values monotonically increase since - * device boot, and may include details about inactive interfaces. - * - * @throws IllegalStateException when problem parsing stats. - */ - public NetworkStats readNetworkStatsSummaryXt() throws IOException { - - // Return xt_bpf stats if qtaguid module is replaced. - if (mUseBpfStats) - return readBpfNetworkStatsDev(); - - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - // return null when kernel doesn't support - if (!mStatsXtIfaceFmt.exists()) return null; - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - ProcFileReader reader = null; - try { - // open and consume header line - reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceFmt)); - reader.finishLine(); - - while (reader.hasMoreData()) { - entry.iface = reader.nextString(); - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - - entry.rxBytes = reader.nextLong(); - entry.rxPackets = reader.nextLong(); - entry.txBytes = reader.nextLong(); - entry.txPackets = reader.nextLong(); - - stats.insertEntry(entry); - reader.finishLine(); - } - } catch (NullPointerException|NumberFormatException e) { - throw protocolExceptionWithCause("problem parsing stats", e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - return stats; - } - - public NetworkStats readNetworkStatsDetail() throws IOException { - return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); - } - - @GuardedBy("mPersistentDataLock") - private void requestSwapActiveStatsMapLocked() throws IOException { - try { - // Do a active map stats swap. Once the swap completes, this code - // can read and clean the inactive map without races. - mBpfNetMaps.swapActiveStatsMap(); - } catch (ServiceSpecificException e) { - throw new IOException(e); - } - } - - /** - * Reads the detailed UID stats based on the provided parameters - * - * @param limitUid the UID to limit this query to - * @param limitIfaces the interfaces to limit this query to. Use {@link - * NetworkStats.INTERFACES_ALL} to select all interfaces - * @param limitTag the tags to limit this query to - * @return the NetworkStats instance containing network statistics at the present time. - */ - public NetworkStats readNetworkStatsDetail( - int limitUid, String[] limitIfaces, int limitTag) throws IOException { - // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other - // code that will acquire other locks within the system server. See b/134244752. - synchronized (mPersistentDataLock) { - // Take a reference. If this gets swapped out, we still have the old reference. - final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos; - // Take a defensive copy. mPersistSnapshot is mutated in some cases below - final NetworkStats prev = mPersistSnapshot.clone(); - - if (USE_NATIVE_PARSING) { - final NetworkStats stats = - new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); - if (mUseBpfStats) { - requestSwapActiveStatsMapLocked(); - // Stats are always read from the inactive map, so they must be read after the - // swap - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); - } - - // BPF stats are incremental; fold into mPersistSnapshot. - mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); - mPersistSnapshot.combineAllValues(stats); - } else { - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); - } - if (VALIDATE_NATIVE_STATS) { - final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, - UID_ALL, INTERFACES_ALL, TAG_ALL); - assertEquals(javaStats, stats); - } - - mPersistSnapshot = stats; - } - } else { - mPersistSnapshot = javaReadNetworkStatsDetail(mStatsXtUid, UID_ALL, INTERFACES_ALL, - TAG_ALL); - } - - NetworkStats adjustedStats = adjustForTunAnd464Xlat(mPersistSnapshot, prev, vpnArray); - - // Filter return values - adjustedStats.filter(limitUid, limitIfaces, limitTag); - return adjustedStats; - } - } - - @GuardedBy("mPersistentDataLock") - private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats, - NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) { - // Calculate delta from last snapshot - final NetworkStats delta = uidDetailStats.subtract(previousStats); - - // Apply 464xlat adjustments before VPN adjustments. If VPNs are using v4 on a v6 only - // network, the overhead is their fault. - // No locking here: apply464xlatAdjustments behaves fine with an add-only - // ConcurrentHashMap. - delta.apply464xlatAdjustments(mStackedIfaces); - - // Migrate data usage over a VPN to the TUN network. - for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.getOwnerUid(), info.getInterface(), - info.getUnderlyingInterfaces()); - // Filter out debug entries as that may lead to over counting. - delta.filterDebugEntries(); - } - - // Update mTunAnd464xlatAdjustedStats with migrated delta. - mTunAnd464xlatAdjustedStats.combineAllValues(delta); - mTunAnd464xlatAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); - - return mTunAnd464xlatAdjustedStats.clone(); - } - - /** - * Parse and return {@link NetworkStats} with UID-level details. Values are - * expected to monotonically increase since device boot. - */ - @VisibleForTesting - public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid, - String[] limitIfaces, int limitTag) - throws IOException { - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - int idx = 1; - int lastIdx = 1; - - ProcFileReader reader = null; - try { - // open and consume header line - reader = new ProcFileReader(new FileInputStream(detailPath)); - reader.finishLine(); - - while (reader.hasMoreData()) { - idx = reader.nextInt(); - if (idx != lastIdx + 1) { - throw new ProtocolException( - "inconsistent idx=" + idx + " after lastIdx=" + lastIdx); - } - lastIdx = idx; - - entry.iface = reader.nextString(); - entry.tag = kernelToTag(reader.nextString()); - entry.uid = reader.nextInt(); - entry.set = reader.nextInt(); - entry.rxBytes = reader.nextLong(); - entry.rxPackets = reader.nextLong(); - entry.txBytes = reader.nextLong(); - entry.txPackets = reader.nextLong(); - - if ((limitIfaces == null || CollectionUtils.contains(limitIfaces, entry.iface)) - && (limitUid == UID_ALL || limitUid == entry.uid) - && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.insertEntry(entry); - } - - reader.finishLine(); - } - } catch (NullPointerException|NumberFormatException e) { - throw protocolExceptionWithCause("problem parsing idx " + idx, e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - - return stats; - } - - public void assertEquals(NetworkStats expected, NetworkStats actual) { - if (expected.size() != actual.size()) { - throw new AssertionError( - "Expected size " + expected.size() + ", actual size " + actual.size()); - } - - NetworkStats.Entry expectedRow = null; - NetworkStats.Entry actualRow = null; - for (int i = 0; i < expected.size(); i++) { - expectedRow = expected.getValues(i, expectedRow); - actualRow = actual.getValues(i, actualRow); - if (!expectedRow.equals(actualRow)) { - throw new AssertionError( - "Expected row " + i + ": " + expectedRow + ", actual row " + actualRow); - } - } - } - - /** - * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming - * format like {@code 0x7fffffff00000000}. - */ - public static int kernelToTag(String string) { - int length = string.length(); - if (length > 10) { - return Long.decode(string.substring(0, length - 8)).intValue(); - } else { - return 0; - } - } - - /** - * Parse statistics from file into given {@link NetworkStats} object. Values - * are expected to monotonically increase since device boot. - */ - @VisibleForTesting - public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path, - int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats); - - @VisibleForTesting - public static native int nativeReadNetworkStatsDev(NetworkStats stats); - - private static ProtocolException protocolExceptionWithCause(String message, Throwable cause) { - ProtocolException pe = new ProtocolException(message); - pe.initCause(cause); - return pe; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java deleted file mode 100644 index fdfc893f57cb..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES; - -import android.app.usage.NetworkStatsManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.DataUsageRequest; -import android.net.NetworkIdentitySet; -import android.net.NetworkStack; -import android.net.NetworkStats; -import android.net.NetworkStatsAccess; -import android.net.NetworkStatsCollection; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.netstats.IUsageCallback; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.os.RemoteException; -import android.util.ArrayMap; -import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Manages observers of {@link NetworkStats}. Allows observers to be notified when - * data usage has been reported in {@link NetworkStatsService}. An observer can set - * a threshold of how much data it cares about to be notified. - */ -class NetworkStatsObservers { - private static final String TAG = "NetworkStatsObservers"; - private static final boolean LOGV = false; - - private static final int MSG_REGISTER = 1; - private static final int MSG_UNREGISTER = 2; - private static final int MSG_UPDATE_STATS = 3; - - // All access to this map must be done from the handler thread. - // indexed by DataUsageRequest#requestId - private final SparseArray<RequestInfo> mDataUsageRequests = new SparseArray<>(); - - // Sequence number of DataUsageRequests - private final AtomicInteger mNextDataUsageRequestId = new AtomicInteger(); - - // Lazily instantiated when an observer is registered. - private volatile Handler mHandler; - - /** - * Creates a wrapper that contains the caller context and a normalized request. - * The request should be returned to the caller app, and the wrapper should be sent to this - * object through #addObserver by the service handler. - * - * <p>It will register the observer asynchronously, so it is safe to call from any thread. - * - * @return the normalized request wrapped within {@link RequestInfo}. - */ - public DataUsageRequest register(Context context, DataUsageRequest inputRequest, - IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { - DataUsageRequest request = buildRequest(context, inputRequest, callingUid); - RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid, - accessLevel); - - if (LOGV) Log.v(TAG, "Registering observer for " + request); - getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo)); - return request; - } - - /** - * Unregister a data usage observer. - * - * <p>It will unregister the observer asynchronously, so it is safe to call from any thread. - */ - public void unregister(DataUsageRequest request, int callingUid) { - getHandler().sendMessage(mHandler.obtainMessage(MSG_UNREGISTER, callingUid, 0 /* ignore */, - request)); - } - - /** - * Updates data usage statistics of registered observers and notifies if limits are reached. - * - * <p>It will update stats asynchronously, so it is safe to call from any thread. - */ - public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot, - ArrayMap<String, NetworkIdentitySet> activeIfaces, - ArrayMap<String, NetworkIdentitySet> activeUidIfaces, - long currentTime) { - StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces, - activeUidIfaces, currentTime); - getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext)); - } - - private Handler getHandler() { - if (mHandler == null) { - synchronized (this) { - if (mHandler == null) { - if (LOGV) Log.v(TAG, "Creating handler"); - mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback); - } - } - } - return mHandler; - } - - @VisibleForTesting - protected Looper getHandlerLooperLocked() { - HandlerThread handlerThread = new HandlerThread(TAG); - handlerThread.start(); - return handlerThread.getLooper(); - } - - private Handler.Callback mHandlerCallback = new Handler.Callback() { - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_REGISTER: { - handleRegister((RequestInfo) msg.obj); - return true; - } - case MSG_UNREGISTER: { - handleUnregister((DataUsageRequest) msg.obj, msg.arg1 /* callingUid */); - return true; - } - case MSG_UPDATE_STATS: { - handleUpdateStats((StatsContext) msg.obj); - return true; - } - default: { - return false; - } - } - } - }; - - /** - * Adds a {@link RequestInfo} as an observer. - * Should only be called from the handler thread otherwise there will be a race condition - * on mDataUsageRequests. - */ - private void handleRegister(RequestInfo requestInfo) { - mDataUsageRequests.put(requestInfo.mRequest.requestId, requestInfo); - } - - /** - * Removes a {@link DataUsageRequest} if the calling uid is authorized. - * Should only be called from the handler thread otherwise there will be a race condition - * on mDataUsageRequests. - */ - private void handleUnregister(DataUsageRequest request, int callingUid) { - RequestInfo requestInfo; - requestInfo = mDataUsageRequests.get(request.requestId); - if (requestInfo == null) { - if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request); - return; - } - if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) { - Log.w(TAG, "Caller uid " + callingUid + " is not owner of " + request); - return; - } - - if (LOGV) Log.v(TAG, "Unregistering " + request); - mDataUsageRequests.remove(request.requestId); - requestInfo.unlinkDeathRecipient(); - requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED); - } - - private void handleUpdateStats(StatsContext statsContext) { - if (mDataUsageRequests.size() == 0) { - return; - } - - for (int i = 0; i < mDataUsageRequests.size(); i++) { - RequestInfo requestInfo = mDataUsageRequests.valueAt(i); - requestInfo.updateStats(statsContext); - } - } - - private DataUsageRequest buildRequest(Context context, DataUsageRequest request, - int callingUid) { - // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to - // avoid too many callbacks. - final long thresholdInBytes = (context.checkPermission( - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid) - == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes - : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes)); - if (thresholdInBytes > request.thresholdInBytes) { - Log.w(TAG, "Threshold was too low for " + request - + ". Overriding to a safer default of " + thresholdInBytes + " bytes"); - } - return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(), - request.template, thresholdInBytes); - } - - private RequestInfo buildRequestInfo(DataUsageRequest request, IUsageCallback callback, - int callingUid, @NetworkStatsAccess.Level int accessLevel) { - if (accessLevel <= NetworkStatsAccess.Level.USER) { - return new UserUsageRequestInfo(this, request, callback, callingUid, - accessLevel); - } else { - // Safety check in case a new access level is added and we forgot to update this - if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) { - throw new IllegalArgumentException( - "accessLevel " + accessLevel + " is less than DEVICESUMMARY."); - } - return new NetworkUsageRequestInfo(this, request, callback, callingUid, - accessLevel); - } - } - - /** - * Tracks information relevant to a data usage observer. - * It will notice when the calling process dies so we can self-expire. - */ - private abstract static class RequestInfo implements IBinder.DeathRecipient { - private final NetworkStatsObservers mStatsObserver; - protected final DataUsageRequest mRequest; - private final IUsageCallback mCallback; - protected final int mCallingUid; - protected final @NetworkStatsAccess.Level int mAccessLevel; - protected NetworkStatsRecorder mRecorder; - protected NetworkStatsCollection mCollection; - - RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - IUsageCallback callback, int callingUid, - @NetworkStatsAccess.Level int accessLevel) { - mStatsObserver = statsObserver; - mRequest = request; - mCallback = callback; - mCallingUid = callingUid; - mAccessLevel = accessLevel; - - try { - mCallback.asBinder().linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } - } - - @Override - public void binderDied() { - if (LOGV) { - Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mCallback + ")"); - } - mStatsObserver.unregister(mRequest, Process.SYSTEM_UID); - callCallback(NetworkStatsManager.CALLBACK_RELEASED); - } - - @Override - public String toString() { - return "RequestInfo from uid:" + mCallingUid - + " for " + mRequest + " accessLevel:" + mAccessLevel; - } - - private void unlinkDeathRecipient() { - mCallback.asBinder().unlinkToDeath(this, 0); - } - - /** - * Update stats given the samples and interface to identity mappings. - */ - private void updateStats(StatsContext statsContext) { - if (mRecorder == null) { - // First run; establish baseline stats - resetRecorder(); - recordSample(statsContext); - return; - } - recordSample(statsContext); - - if (checkStats()) { - resetRecorder(); - callCallback(NetworkStatsManager.CALLBACK_LIMIT_REACHED); - } - } - - private void callCallback(int callbackType) { - try { - if (LOGV) { - Log.v(TAG, "sending notification " + callbackTypeToName(callbackType) - + " for " + mRequest); - } - switch (callbackType) { - case NetworkStatsManager.CALLBACK_LIMIT_REACHED: - mCallback.onThresholdReached(mRequest); - break; - case NetworkStatsManager.CALLBACK_RELEASED: - mCallback.onCallbackReleased(mRequest); - break; - } - } catch (RemoteException e) { - // May occur naturally in the race of binder death. - Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest); - } - } - - private void resetRecorder() { - mRecorder = new NetworkStatsRecorder(); - mCollection = mRecorder.getSinceBoot(); - } - - protected abstract boolean checkStats(); - - protected abstract void recordSample(StatsContext statsContext); - - private String callbackTypeToName(int callbackType) { - switch (callbackType) { - case NetworkStatsManager.CALLBACK_LIMIT_REACHED: - return "LIMIT_REACHED"; - case NetworkStatsManager.CALLBACK_RELEASED: - return "RELEASED"; - default: - return "UNKNOWN"; - } - } - } - - private static class NetworkUsageRequestInfo extends RequestInfo { - NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - IUsageCallback callback, int callingUid, - @NetworkStatsAccess.Level int accessLevel) { - super(statsObserver, request, callback, callingUid, accessLevel); - } - - @Override - protected boolean checkStats() { - long bytesSoFar = getTotalBytesForNetwork(mRequest.template); - if (LOGV) { - Log.v(TAG, bytesSoFar + " bytes so far since notification for " - + mRequest.template); - } - if (bytesSoFar > mRequest.thresholdInBytes) { - return true; - } - return false; - } - - @Override - protected void recordSample(StatsContext statsContext) { - // Recorder does not need to be locked in this context since only the handler - // thread will update it. We pass a null VPN array because usage is aggregated by uid - // for this snapshot, so VPN traffic can't be reattributed to responsible apps. - mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces, - statsContext.mCurrentTime); - } - - /** - * Reads stats matching the given template. {@link NetworkStatsCollection} will aggregate - * over all buckets, which in this case should be only one since we built it big enough - * that it will outlive the caller. If it doesn't, then there will be multiple buckets. - */ - private long getTotalBytesForNetwork(NetworkTemplate template) { - NetworkStats stats = mCollection.getSummary(template, - Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, - mAccessLevel, mCallingUid); - return stats.getTotalBytes(); - } - } - - private static class UserUsageRequestInfo extends RequestInfo { - UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - IUsageCallback callback, int callingUid, - @NetworkStatsAccess.Level int accessLevel) { - super(statsObserver, request, callback, callingUid, accessLevel); - } - - @Override - protected boolean checkStats() { - int[] uidsToMonitor = mCollection.getRelevantUids(mAccessLevel, mCallingUid); - - for (int i = 0; i < uidsToMonitor.length; i++) { - long bytesSoFar = getTotalBytesForNetworkUid(mRequest.template, uidsToMonitor[i]); - if (bytesSoFar > mRequest.thresholdInBytes) { - return true; - } - } - return false; - } - - @Override - protected void recordSample(StatsContext statsContext) { - // Recorder does not need to be locked in this context since only the handler - // thread will update it. We pass the VPN info so VPN traffic is reattributed to - // responsible apps. - mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces, - statsContext.mCurrentTime); - } - - /** - * Reads all stats matching the given template and uid. Ther history will likely only - * contain one bucket per ident since we build it big enough that it will outlive the - * caller lifetime. - */ - private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) { - try { - NetworkStatsHistory history = mCollection.getHistory(template, null, uid, - NetworkStats.SET_ALL, NetworkStats.TAG_NONE, - NetworkStatsHistory.FIELD_ALL, - Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, - mAccessLevel, mCallingUid); - return history.getTotalBytes(); - } catch (SecurityException e) { - if (LOGV) { - Log.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid " - + uid); - } - return 0; - } - } - } - - private static class StatsContext { - NetworkStats mXtSnapshot; - NetworkStats mUidSnapshot; - ArrayMap<String, NetworkIdentitySet> mActiveIfaces; - ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces; - long mCurrentTime; - - StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot, - ArrayMap<String, NetworkIdentitySet> activeIfaces, - ArrayMap<String, NetworkIdentitySet> activeUidIfaces, - long currentTime) { - mXtSnapshot = xtSnapshot; - mUidSnapshot = uidSnapshot; - mActiveIfaces = activeIfaces; - mActiveUidIfaces = activeUidIfaces; - mCurrentTime = currentTime; - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java deleted file mode 100644 index f62765d07427..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static android.net.NetworkStats.TAG_NONE; -import static android.net.TrafficStats.KB_IN_BYTES; -import static android.net.TrafficStats.MB_IN_BYTES; -import static android.text.format.DateUtils.YEAR_IN_MILLIS; - -import android.net.NetworkIdentitySet; -import android.net.NetworkStats; -import android.net.NetworkStats.NonMonotonicObserver; -import android.net.NetworkStatsAccess; -import android.net.NetworkStatsCollection; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.TrafficStats; -import android.os.Binder; -import android.os.DropBoxManager; -import android.service.NetworkStatsRecorderProto; -import android.util.IndentingPrintWriter; -import android.util.Log; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.util.FileRotator; -import com.android.net.module.util.NetworkStatsUtils; - -import libcore.io.IoUtils; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.lang.ref.WeakReference; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; - -/** - * Logic to record deltas between periodic {@link NetworkStats} snapshots into - * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. - * Keeps pending changes in memory until they pass a specific threshold, in - * bytes. Uses {@link FileRotator} for persistence logic if present. - * <p> - * Not inherently thread safe. - */ -public class NetworkStatsRecorder { - private static final String TAG = "NetworkStatsRecorder"; - private static final boolean LOGD = false; - private static final boolean LOGV = false; - - private static final String TAG_NETSTATS_DUMP = "netstats_dump"; - - /** Dump before deleting in {@link #recoverFromWtf()}. */ - private static final boolean DUMP_BEFORE_DELETE = true; - - private final FileRotator mRotator; - private final NonMonotonicObserver<String> mObserver; - private final DropBoxManager mDropBox; - private final String mCookie; - - private final long mBucketDuration; - private final boolean mOnlyTags; - - private long mPersistThresholdBytes = 2 * MB_IN_BYTES; - private NetworkStats mLastSnapshot; - - private final NetworkStatsCollection mPending; - private final NetworkStatsCollection mSinceBoot; - - private final CombiningRewriter mPendingRewriter; - - private WeakReference<NetworkStatsCollection> mComplete; - - /** - * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}. - */ - public NetworkStatsRecorder() { - mRotator = null; - mObserver = null; - mDropBox = null; - mCookie = null; - - // set the bucket big enough to have all data in one bucket, but allow some - // slack to avoid overflow - mBucketDuration = YEAR_IN_MILLIS; - mOnlyTags = false; - - mPending = null; - mSinceBoot = new NetworkStatsCollection(mBucketDuration); - - mPendingRewriter = null; - } - - /** - * Persisted recorder. - */ - public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer, - DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) { - mRotator = Objects.requireNonNull(rotator, "missing FileRotator"); - mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver"); - mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager"); - mCookie = cookie; - - mBucketDuration = bucketDuration; - mOnlyTags = onlyTags; - - mPending = new NetworkStatsCollection(bucketDuration); - mSinceBoot = new NetworkStatsCollection(bucketDuration); - - mPendingRewriter = new CombiningRewriter(mPending); - } - - public void setPersistThreshold(long thresholdBytes) { - if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes); - mPersistThresholdBytes = NetworkStatsUtils.constrain( - thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES); - } - - public void resetLocked() { - mLastSnapshot = null; - if (mPending != null) { - mPending.reset(); - } - if (mSinceBoot != null) { - mSinceBoot.reset(); - } - if (mComplete != null) { - mComplete.clear(); - } - } - - public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) { - return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE, - NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null); - } - - public NetworkStatsCollection getSinceBoot() { - return mSinceBoot; - } - - /** - * Load complete history represented by {@link FileRotator}. Caches - * internally as a {@link WeakReference}, and updated with future - * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long - * as reference is valid. - */ - public NetworkStatsCollection getOrLoadCompleteLocked() { - Objects.requireNonNull(mRotator, "missing FileRotator"); - NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; - if (res == null) { - res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE); - mComplete = new WeakReference<NetworkStatsCollection>(res); - } - return res; - } - - public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) { - Objects.requireNonNull(mRotator, "missing FileRotator"); - NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; - if (res == null) { - res = loadLocked(start, end); - } - return res; - } - - private NetworkStatsCollection loadLocked(long start, long end) { - if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie); - final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration); - try { - mRotator.readMatching(res, start, end); - res.recordCollection(mPending); - } catch (IOException e) { - Log.wtf(TAG, "problem completely reading network stats", e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem completely reading network stats", e); - recoverFromWtf(); - } - return res; - } - - /** - * Record any delta that occurred since last {@link NetworkStats} snapshot, using the given - * {@link Map} to identify network interfaces. First snapshot is considered bootstrap, and is - * not counted as delta. - */ - public void recordSnapshotLocked(NetworkStats snapshot, - Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) { - final HashSet<String> unknownIfaces = new HashSet<>(); - - // skip recording when snapshot missing - if (snapshot == null) return; - - // assume first snapshot is bootstrap and don't record - if (mLastSnapshot == null) { - mLastSnapshot = snapshot; - return; - } - - final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; - - final NetworkStats delta = NetworkStats.subtract( - snapshot, mLastSnapshot, mObserver, mCookie); - final long end = currentTimeMillis; - final long start = end - delta.getElapsedRealtime(); - - NetworkStats.Entry entry = null; - for (int i = 0; i < delta.size(); i++) { - entry = delta.getValues(i, entry); - - // As a last-ditch check, report any negative values and - // clamp them so recording below doesn't croak. - if (entry.isNegative()) { - if (mObserver != null) { - mObserver.foundNonMonotonic(delta, i, mCookie); - } - entry.rxBytes = Math.max(entry.rxBytes, 0); - entry.rxPackets = Math.max(entry.rxPackets, 0); - entry.txBytes = Math.max(entry.txBytes, 0); - entry.txPackets = Math.max(entry.txPackets, 0); - entry.operations = Math.max(entry.operations, 0); - } - - final NetworkIdentitySet ident = ifaceIdent.get(entry.iface); - if (ident == null) { - unknownIfaces.add(entry.iface); - continue; - } - - // skip when no delta occurred - if (entry.isEmpty()) continue; - - // only record tag data when requested - if ((entry.tag == TAG_NONE) != mOnlyTags) { - if (mPending != null) { - mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); - } - - // also record against boot stats when present - if (mSinceBoot != null) { - mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); - } - - // also record against complete dataset when present - if (complete != null) { - complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); - } - } - } - - mLastSnapshot = snapshot; - - if (LOGV && unknownIfaces.size() > 0) { - Log.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); - } - } - - /** - * Consider persisting any pending deltas, if they are beyond - * {@link #mPersistThresholdBytes}. - */ - public void maybePersistLocked(long currentTimeMillis) { - Objects.requireNonNull(mRotator, "missing FileRotator"); - final long pendingBytes = mPending.getTotalBytes(); - if (pendingBytes >= mPersistThresholdBytes) { - forcePersistLocked(currentTimeMillis); - } else { - mRotator.maybeRotate(currentTimeMillis); - } - } - - /** - * Force persisting any pending deltas. - */ - public void forcePersistLocked(long currentTimeMillis) { - Objects.requireNonNull(mRotator, "missing FileRotator"); - if (mPending.isDirty()) { - if (LOGD) Log.d(TAG, "forcePersistLocked() writing for " + mCookie); - try { - mRotator.rewriteActive(mPendingRewriter, currentTimeMillis); - mRotator.maybeRotate(currentTimeMillis); - mPending.reset(); - } catch (IOException e) { - Log.wtf(TAG, "problem persisting pending stats", e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem persisting pending stats", e); - recoverFromWtf(); - } - } - } - - /** - * Remove the given UID from all {@link FileRotator} history, migrating it - * to {@link TrafficStats#UID_REMOVED}. - */ - public void removeUidsLocked(int[] uids) { - if (mRotator != null) { - try { - // Rewrite all persisted data to migrate UID stats - mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids)); - } catch (IOException e) { - Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); - recoverFromWtf(); - } - } - - // Remove any pending stats - if (mPending != null) { - mPending.removeUids(uids); - } - if (mSinceBoot != null) { - mSinceBoot.removeUids(uids); - } - - // Clear UID from current stats snapshot - if (mLastSnapshot != null) { - mLastSnapshot.removeUids(uids); - } - - final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; - if (complete != null) { - complete.removeUids(uids); - } - } - - /** - * Rewriter that will combine current {@link NetworkStatsCollection} values - * with anything read from disk, and write combined set to disk. Clears the - * original {@link NetworkStatsCollection} when finished writing. - */ - private static class CombiningRewriter implements FileRotator.Rewriter { - private final NetworkStatsCollection mCollection; - - public CombiningRewriter(NetworkStatsCollection collection) { - mCollection = Objects.requireNonNull(collection, "missing NetworkStatsCollection"); - } - - @Override - public void reset() { - // ignored - } - - @Override - public void read(InputStream in) throws IOException { - mCollection.read(in); - } - - @Override - public boolean shouldWrite() { - return true; - } - - @Override - public void write(OutputStream out) throws IOException { - mCollection.write(out); - mCollection.reset(); - } - } - - /** - * Rewriter that will remove any {@link NetworkStatsHistory} attributed to - * the requested UID, only writing data back when modified. - */ - public static class RemoveUidRewriter implements FileRotator.Rewriter { - private final NetworkStatsCollection mTemp; - private final int[] mUids; - - public RemoveUidRewriter(long bucketDuration, int[] uids) { - mTemp = new NetworkStatsCollection(bucketDuration); - mUids = uids; - } - - @Override - public void reset() { - mTemp.reset(); - } - - @Override - public void read(InputStream in) throws IOException { - mTemp.read(in); - mTemp.clearDirty(); - mTemp.removeUids(mUids); - } - - @Override - public boolean shouldWrite() { - return mTemp.isDirty(); - } - - @Override - public void write(OutputStream out) throws IOException { - mTemp.write(out); - } - } - - public void importLegacyNetworkLocked(File file) throws IOException { - Objects.requireNonNull(mRotator, "missing FileRotator"); - - // legacy file still exists; start empty to avoid double importing - mRotator.deleteAll(); - - final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); - collection.readLegacyNetwork(file); - - final long startMillis = collection.getStartMillis(); - final long endMillis = collection.getEndMillis(); - - if (!collection.isEmpty()) { - // process legacy data, creating active file at starting time, then - // using end time to possibly trigger rotation. - mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); - mRotator.maybeRotate(endMillis); - } - } - - public void importLegacyUidLocked(File file) throws IOException { - Objects.requireNonNull(mRotator, "missing FileRotator"); - - // legacy file still exists; start empty to avoid double importing - mRotator.deleteAll(); - - final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); - collection.readLegacyUid(file, mOnlyTags); - - final long startMillis = collection.getStartMillis(); - final long endMillis = collection.getEndMillis(); - - if (!collection.isEmpty()) { - // process legacy data, creating active file at starting time, then - // using end time to possibly trigger rotation. - mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); - mRotator.maybeRotate(endMillis); - } - } - - public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) { - if (mPending != null) { - pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes()); - } - if (fullHistory) { - pw.println("Complete history:"); - getOrLoadCompleteLocked().dump(pw); - } else { - pw.println("History since boot:"); - mSinceBoot.dump(pw); - } - } - - public void dumpDebugLocked(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, - mPending.getTotalBytes()); - } - getOrLoadCompleteLocked().dumpDebug(proto, - NetworkStatsRecorderProto.COMPLETE_HISTORY); - proto.end(start); - } - - public void dumpCheckin(PrintWriter pw, long start, long end) { - // Only load and dump stats from the requested window - getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end); - } - - /** - * Recover from {@link FileRotator} failure by dumping state to - * {@link DropBoxManager} and deleting contents. - */ - private void recoverFromWtf() { - if (DUMP_BEFORE_DELETE) { - final ByteArrayOutputStream os = new ByteArrayOutputStream(); - try { - mRotator.dumpAll(os); - } catch (IOException e) { - // ignore partial contents - os.reset(); - } finally { - IoUtils.closeQuietly(os); - } - mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0); - } - - mRotator.deleteAll(); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java deleted file mode 100644 index e3794e441a23..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +++ /dev/null @@ -1,2528 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static android.Manifest.permission.NETWORK_STATS_PROVIDER; -import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; -import static android.Manifest.permission.UPDATE_DEVICE_STATS; -import static android.app.usage.NetworkStatsManager.PREFIX_DEV; -import static android.content.Intent.ACTION_SHUTDOWN; -import static android.content.Intent.ACTION_UID_REMOVED; -import static android.content.Intent.ACTION_USER_REMOVED; -import static android.content.Intent.EXTRA_UID; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; -import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.IFACE_VT; -import static android.net.NetworkStats.INTERFACES_ALL; -import static android.net.NetworkStats.METERED_ALL; -import static android.net.NetworkStats.ROAMING_ALL; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.SET_FOREGROUND; -import static android.net.NetworkStats.STATS_PER_IFACE; -import static android.net.NetworkStats.STATS_PER_UID; -import static android.net.NetworkStats.TAG_ALL; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.FIELD_ALL; -import static android.net.NetworkTemplate.buildTemplateMobileWildcard; -import static android.net.NetworkTemplate.buildTemplateWifiWildcard; -import static android.net.TrafficStats.KB_IN_BYTES; -import static android.net.TrafficStats.MB_IN_BYTES; -import static android.net.TrafficStats.UID_TETHERING; -import static android.net.TrafficStats.UNSUPPORTED; -import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; -import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; -import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT; -import static android.os.Trace.TRACE_TAG_NETWORK; -import static android.system.OsConstants.ENOENT; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static android.text.format.DateUtils.DAY_IN_MILLIS; -import static android.text.format.DateUtils.HOUR_IN_MILLIS; -import static android.text.format.DateUtils.MINUTE_IN_MILLIS; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; - -import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; -import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.TargetApi; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.usage.NetworkStatsManager; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.net.DataUsageRequest; -import android.net.INetd; -import android.net.INetworkStatsService; -import android.net.INetworkStatsSession; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkIdentity; -import android.net.NetworkIdentitySet; -import android.net.NetworkPolicyManager; -import android.net.NetworkSpecifier; -import android.net.NetworkStack; -import android.net.NetworkStateSnapshot; -import android.net.NetworkStats; -import android.net.NetworkStats.NonMonotonicObserver; -import android.net.NetworkStatsAccess; -import android.net.NetworkStatsCollection; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.TelephonyNetworkSpecifier; -import android.net.TetherStatsParcel; -import android.net.TetheringManager; -import android.net.TrafficStats; -import android.net.UnderlyingNetworkInfo; -import android.net.Uri; -import android.net.netstats.IUsageCallback; -import android.net.netstats.provider.INetworkStatsProvider; -import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProvider; -import android.os.Binder; -import android.os.Build; -import android.os.DropBoxManager; -import android.os.Environment; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.os.SystemClock; -import android.os.Trace; -import android.os.UserHandle; -import android.provider.Settings; -import android.provider.Settings.Global; -import android.service.NetworkInterfaceProto; -import android.service.NetworkStatsServiceDumpProto; -import android.system.ErrnoException; -import android.telephony.PhoneStateListener; -import android.telephony.SubscriptionPlan; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.EventLog; -import android.util.IndentingPrintWriter; -import android.util.Log; -import android.util.SparseIntArray; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.FileRotator; -import com.android.net.module.util.BaseNetdUnsolicitedEventListener; -import com.android.net.module.util.BestClock; -import com.android.net.module.util.BinderUtils; -import com.android.net.module.util.BpfMap; -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.IBpfMap; -import com.android.net.module.util.LocationPermissionChecker; -import com.android.net.module.util.NetworkStatsUtils; -import com.android.net.module.util.PermissionUtils; -import com.android.net.module.util.Struct.U32; -import com.android.net.module.util.Struct.U8; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.time.Clock; -import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - -/** - * Collect and persist detailed network statistics, and provide this data to - * other system services. - */ -@TargetApi(Build.VERSION_CODES.TIRAMISU) -public class NetworkStatsService extends INetworkStatsService.Stub { - static { - System.loadLibrary("service-connectivity"); - } - - static final String TAG = "NetworkStats"; - static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); - static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); - - // Perform polling and persist all (FLAG_PERSIST_ALL). - private static final int MSG_PERFORM_POLL = 1; - // Perform polling, persist network, and register the global alert again. - private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; - private static final int MSG_NOTIFY_NETWORK_STATUS = 3; - // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent - // deadlock. - private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4; - - /** Flags to control detail level of poll event. */ - private static final int FLAG_PERSIST_NETWORK = 0x1; - private static final int FLAG_PERSIST_UID = 0x2; - private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; - private static final int FLAG_PERSIST_FORCE = 0x100; - - /** - * When global alert quota is high, wait for this delay before processing each polling, - * and do not schedule further polls once there is already one queued. - * This avoids firing the global alert too often on devices with high transfer speeds and - * high quota. - */ - private static final int DEFAULT_PERFORM_POLL_DELAY_MS = 1000; - - private static final String TAG_NETSTATS_ERROR = "netstats_error"; - - /** - * EventLog tags used when logging into the event log. Note the values must be sync with - * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct - * name translation. - */ - private static final int LOG_TAG_NETSTATS_MOBILE_SAMPLE = 51100; - private static final int LOG_TAG_NETSTATS_WIFI_SAMPLE = 51101; - - // TODO: Replace the hardcoded string and move it into ConnectivitySettingsManager. - private static final String NETSTATS_COMBINE_SUBTYPE_ENABLED = - "netstats_combine_subtype_enabled"; - - // This is current path but may be changed soon. - private static final String UID_COUNTERSET_MAP_PATH = - "/sys/fs/bpf/map_netd_uid_counterset_map"; - private static final String COOKIE_TAG_MAP_PATH = - "/sys/fs/bpf/map_netd_cookie_tag_map"; - private static final String APP_UID_STATS_MAP_PATH = - "/sys/fs/bpf/map_netd_app_uid_stats_map"; - private static final String STATS_MAP_A_PATH = - "/sys/fs/bpf/map_netd_stats_map_A"; - private static final String STATS_MAP_B_PATH = - "/sys/fs/bpf/map_netd_stats_map_B"; - - private final Context mContext; - private final NetworkStatsFactory mStatsFactory; - private final AlarmManager mAlarmManager; - private final Clock mClock; - private final NetworkStatsSettings mSettings; - private final NetworkStatsObservers mStatsObservers; - - private final File mSystemDir; - private final File mBaseDir; - - private final PowerManager.WakeLock mWakeLock; - - private final ContentObserver mContentObserver; - private final ContentResolver mContentResolver; - - protected INetd mNetd; - private final AlertObserver mAlertObserver = new AlertObserver(); - - @VisibleForTesting - public static final String ACTION_NETWORK_STATS_POLL = - "com.android.server.action.NETWORK_STATS_POLL"; - public static final String ACTION_NETWORK_STATS_UPDATED = - "com.android.server.action.NETWORK_STATS_UPDATED"; - - private PendingIntent mPollIntent; - - /** - * Settings that can be changed externally. - */ - public interface NetworkStatsSettings { - long getPollInterval(); - long getPollDelay(); - boolean getSampleEnabled(); - boolean getAugmentEnabled(); - /** - * When enabled, all mobile data is reported under {@link NetworkTemplate#NETWORK_TYPE_ALL}. - * When disabled, mobile data is broken down by a granular ratType representative of the - * actual ratType. {@see android.app.usage.NetworkStatsManager#getCollapsedRatType}. - * Enabling this decreases the level of detail but saves performance, disk space and - * amount of data logged. - */ - boolean getCombineSubtypeEnabled(); - - class Config { - public final long bucketDuration; - public final long rotateAgeMillis; - public final long deleteAgeMillis; - - public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) { - this.bucketDuration = bucketDuration; - this.rotateAgeMillis = rotateAgeMillis; - this.deleteAgeMillis = deleteAgeMillis; - } - } - - Config getDevConfig(); - Config getXtConfig(); - Config getUidConfig(); - Config getUidTagConfig(); - - long getGlobalAlertBytes(long def); - long getDevPersistBytes(long def); - long getXtPersistBytes(long def); - long getUidPersistBytes(long def); - long getUidTagPersistBytes(long def); - } - - private final Object mStatsLock = new Object(); - - /** Set of currently active ifaces. */ - @GuardedBy("mStatsLock") - private final ArrayMap<String, NetworkIdentitySet> mActiveIfaces = new ArrayMap<>(); - - /** Set of currently active ifaces for UID stats. */ - @GuardedBy("mStatsLock") - private final ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces = new ArrayMap<>(); - - /** Current default active iface. */ - @GuardedBy("mStatsLock") - private String mActiveIface; - - /** Set of any ifaces associated with mobile networks since boot. */ - private volatile String[] mMobileIfaces = new String[0]; - - /** Set of any ifaces associated with wifi networks since boot. */ - private volatile String[] mWifiIfaces = new String[0]; - - /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */ - @GuardedBy("mStatsLock") - private Network[] mDefaultNetworks = new Network[0]; - - /** Last states of all networks sent from ConnectivityService. */ - @GuardedBy("mStatsLock") - @Nullable - private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null; - - private final DropBoxNonMonotonicObserver mNonMonotonicObserver = - new DropBoxNonMonotonicObserver(); - - private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; - private final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList = - new CopyOnWriteArrayList<>(); - /** Semaphore used to wait for stats provider to respond to request stats update. */ - private final Semaphore mStatsProviderSem = new Semaphore(0, true); - - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mDevRecorder; - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mXtRecorder; - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mUidRecorder; - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mUidTagRecorder; - - /** Cached {@link #mXtRecorder} stats. */ - @GuardedBy("mStatsLock") - private NetworkStatsCollection mXtStatsCached; - - /** - * Current counter sets for each UID. - * TODO: maybe remove mActiveUidCounterSet and read UidCouneterSet value from mUidCounterSetMap - * directly ? But if mActiveUidCounterSet would be accessed very frequently, maybe keep - * mActiveUidCounterSet to avoid accessing kernel too frequently. - */ - private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); - private final IBpfMap<U32, U8> mUidCounterSetMap; - private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap; - private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapA; - private final IBpfMap<StatsMapKey, StatsMapValue> mStatsMapB; - private final IBpfMap<UidStatsMapKey, StatsMapValue> mAppUidStatsMap; - - /** Data layer operation counters for splicing into other structures. */ - private NetworkStats mUidOperations = new NetworkStats(0L, 10); - - @NonNull - private final Handler mHandler; - - private volatile boolean mSystemReady; - private long mPersistThreshold = 2 * MB_IN_BYTES; - private long mGlobalAlertBytes; - - private static final long POLL_RATE_LIMIT_MS = 15_000; - - private long mLastStatsSessionPoll; - - /** Map from UID to number of opened sessions */ - @GuardedBy("mOpenSessionCallsPerUid") - private final SparseIntArray mOpenSessionCallsPerUid = new SparseIntArray(); - - private final static int DUMP_STATS_SESSION_COUNT = 20; - - @NonNull - private final Dependencies mDeps; - - @NonNull - private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; - - @NonNull - private final LocationPermissionChecker mLocationPermissionChecker; - - @NonNull - private final BpfInterfaceMapUpdater mInterfaceMapUpdater; - - private static @NonNull File getDefaultSystemDir() { - return new File(Environment.getDataDirectory(), "system"); - } - - private static @NonNull File getDefaultBaseDir() { - File baseDir = new File(getDefaultSystemDir(), "netstats"); - baseDir.mkdirs(); - return baseDir; - } - - private static @NonNull Clock getDefaultClock() { - return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(), - Clock.systemUTC()); - } - - private final class NetworkStatsHandler extends Handler { - NetworkStatsHandler(@NonNull Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_PERFORM_POLL: { - performPoll(FLAG_PERSIST_ALL); - break; - } - case MSG_NOTIFY_NETWORK_STATUS: { - // If no cached states, ignore. - if (mLastNetworkStateSnapshots == null) break; - // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. - handleNotifyNetworkStatus( - mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); - break; - } - case MSG_PERFORM_POLL_REGISTER_ALERT: { - performPoll(FLAG_PERSIST_NETWORK); - registerGlobalAlert(); - break; - } - case MSG_BROADCAST_NETWORK_STATS_UPDATED: { - final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); - updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, - READ_NETWORK_USAGE_HISTORY); - break; - } - } - } - } - - /** Creates a new NetworkStatsService */ - public static NetworkStatsService create(Context context) { - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - PowerManager.WakeLock wakeLock = - powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - final INetd netd = INetd.Stub.asInterface( - (IBinder) context.getSystemService(Context.NETD_SERVICE)); - final NetworkStatsService service = new NetworkStatsService(context, - INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)), - alarmManager, wakeLock, getDefaultClock(), - new DefaultNetworkStatsSettings(), new NetworkStatsFactory(context), - new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), - new Dependencies()); - - return service; - } - - // This must not be called outside of tests, even within the same package, as this constructor - // does not register the local service. Use the create() helper above. - @VisibleForTesting - NetworkStatsService(Context context, INetd netd, AlarmManager alarmManager, - PowerManager.WakeLock wakeLock, Clock clock, NetworkStatsSettings settings, - NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir, @NonNull Dependencies deps) { - mContext = Objects.requireNonNull(context, "missing Context"); - mNetd = Objects.requireNonNull(netd, "missing Netd"); - mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); - mClock = Objects.requireNonNull(clock, "missing Clock"); - mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); - mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock"); - mStatsFactory = Objects.requireNonNull(factory, "missing factory"); - mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); - mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir"); - mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir"); - mDeps = Objects.requireNonNull(deps, "missing Dependencies"); - - final HandlerThread handlerThread = mDeps.makeHandlerThread(); - handlerThread.start(); - mHandler = new NetworkStatsHandler(handlerThread.getLooper()); - mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, - (command) -> mHandler.post(command) , this); - mContentResolver = mContext.getContentResolver(); - mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, - mNetworkStatsSubscriptionsMonitor); - mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); - mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); - mInterfaceMapUpdater.start(); - mUidCounterSetMap = mDeps.getUidCounterSetMap(); - mCookieTagMap = mDeps.getCookieTagMap(); - mStatsMapA = mDeps.getStatsMapA(); - mStatsMapB = mDeps.getStatsMapB(); - mAppUidStatsMap = mDeps.getAppUidStatsMap(); - } - - /** - * Dependencies of NetworkStatsService, for injection in tests. - */ - // TODO: Move more stuff into dependencies object. - @VisibleForTesting - public static class Dependencies { - /** - * Create a HandlerThread to use in NetworkStatsService. - */ - @NonNull - public HandlerThread makeHandlerThread() { - return new HandlerThread(TAG); - } - - /** - * Create a {@link NetworkStatsSubscriptionsMonitor}, can be used to monitor RAT change - * event in NetworkStatsService. - */ - @NonNull - public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, - @NonNull Executor executor, @NonNull NetworkStatsService service) { - // TODO: Update RatType passively in NSS, instead of querying into the monitor - // when notifyNetworkStatus. - return new NetworkStatsSubscriptionsMonitor(context, executor, - (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); - } - - /** - * Create a ContentObserver instance which is used to observe settings changes, - * and dispatch onChange events on handler thread. - */ - public @NonNull ContentObserver makeContentObserver(@NonNull Handler handler, - @NonNull NetworkStatsSettings settings, - @NonNull NetworkStatsSubscriptionsMonitor monitor) { - return new ContentObserver(handler) { - @Override - public void onChange(boolean selfChange, @NonNull Uri uri) { - if (!settings.getCombineSubtypeEnabled()) { - monitor.start(); - } else { - monitor.stop(); - } - } - }; - } - - /** - * @see LocationPermissionChecker - */ - public LocationPermissionChecker makeLocationPermissionChecker(final Context context) { - return new LocationPermissionChecker(context); - } - - /** Create BpfInterfaceMapUpdater to update bpf interface map. */ - @NonNull - public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater( - @NonNull Context ctx, @NonNull Handler handler) { - return new BpfInterfaceMapUpdater(ctx, handler); - } - - /** Get counter sets map for each UID. */ - public IBpfMap<U32, U8> getUidCounterSetMap() { - try { - return new BpfMap<U32, U8>(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR, - U32.class, U8.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open uid counter set map: " + e); - return null; - } - } - - /** Gets the cookie tag map */ - public IBpfMap<CookieTagMapKey, CookieTagMapValue> getCookieTagMap() { - try { - return new BpfMap<CookieTagMapKey, CookieTagMapValue>(COOKIE_TAG_MAP_PATH, - BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open cookie tag map: " + e); - return null; - } - } - - /** Gets stats map A */ - public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapA() { - try { - return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_A_PATH, - BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open stats map A: " + e); - return null; - } - } - - /** Gets stats map B */ - public IBpfMap<StatsMapKey, StatsMapValue> getStatsMapB() { - try { - return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_B_PATH, - BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open stats map B: " + e); - return null; - } - } - - /** Gets the uid stats map */ - public IBpfMap<UidStatsMapKey, StatsMapValue> getAppUidStatsMap() { - try { - return new BpfMap<UidStatsMapKey, StatsMapValue>(APP_UID_STATS_MAP_PATH, - BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open app uid stats map: " + e); - return null; - } - } - } - - /** - * Observer that watches for {@link INetdUnsolicitedEventListener} alerts. - */ - @VisibleForTesting - public class AlertObserver extends BaseNetdUnsolicitedEventListener { - @Override - public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { - PermissionUtils.enforceNetworkStackPermission(mContext); - - if (LIMIT_GLOBAL_ALERT.equals(alertName)) { - // kick off background poll to collect network stats unless there is already - // such a call pending; UID stats are handled during normal polling interval. - if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { - mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, - mSettings.getPollDelay()); - } - } - } - } - - public void systemReady() { - synchronized (mStatsLock) { - mSystemReady = true; - - // create data recorders along with historical rotators - mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false); - mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false); - mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false); - mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true); - - updatePersistThresholdsLocked(); - - // upgrade any legacy stats, migrating them to rotated files - maybeUpgradeLegacyStatsLocked(); - - // read historical network stats from disk, since policy service - // might need them right away. - mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked(); - - // bootstrap initial stats to prevent double-counting later - bootstrapStatsLocked(); - } - - // watch for tethering changes - final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); - tetheringManager.registerTetheringEventCallback( - (command) -> mHandler.post(command), mTetherListener); - - // listen for periodic polling events - final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); - mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler); - - // listen for uid removal to clean stats - final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED); - mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler); - - // listen for user changes to clean stats - final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED); - mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); - - // persist stats during clean shutdown - final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN); - mContext.registerReceiver(mShutdownReceiver, shutdownFilter); - - try { - mNetd.registerUnsolicitedEventListener(mAlertObserver); - } catch (RemoteException | ServiceSpecificException e) { - Log.wtf(TAG, "Error registering event listener :", e); - } - - // schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}. - final PendingIntent pollIntent = - PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), - PendingIntent.FLAG_IMMUTABLE); - - final long currentRealtime = SystemClock.elapsedRealtime(); - mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, - mSettings.getPollInterval(), pollIntent); - - mContentResolver.registerContentObserver(Settings.Global - .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED), - false /* notifyForDescendants */, mContentObserver); - - // Post a runnable on handler thread to call onChange(). It's for getting current value of - // NETSTATS_COMBINE_SUBTYPE_ENABLED to decide start or stop monitoring RAT type changes. - mHandler.post(() -> mContentObserver.onChange(false, Settings.Global - .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED))); - - registerGlobalAlert(); - } - - private NetworkStatsRecorder buildRecorder( - String prefix, NetworkStatsSettings.Config config, boolean includeTags) { - final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService( - Context.DROPBOX_SERVICE); - return new NetworkStatsRecorder(new FileRotator( - mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), - mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags); - } - - @GuardedBy("mStatsLock") - private void shutdownLocked() { - final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); - tetheringManager.unregisterTetheringEventCallback(mTetherListener); - mContext.unregisterReceiver(mPollReceiver); - mContext.unregisterReceiver(mRemovedReceiver); - mContext.unregisterReceiver(mUserReceiver); - mContext.unregisterReceiver(mShutdownReceiver); - - if (!mSettings.getCombineSubtypeEnabled()) { - mNetworkStatsSubscriptionsMonitor.stop(); - } - - mContentResolver.unregisterContentObserver(mContentObserver); - - final long currentTime = mClock.millis(); - - // persist any pending stats - mDevRecorder.forcePersistLocked(currentTime); - mXtRecorder.forcePersistLocked(currentTime); - mUidRecorder.forcePersistLocked(currentTime); - mUidTagRecorder.forcePersistLocked(currentTime); - - mSystemReady = false; - } - - @GuardedBy("mStatsLock") - private void maybeUpgradeLegacyStatsLocked() { - File file; - try { - file = new File(mSystemDir, "netstats.bin"); - if (file.exists()) { - mDevRecorder.importLegacyNetworkLocked(file); - file.delete(); - } - - file = new File(mSystemDir, "netstats_xt.bin"); - if (file.exists()) { - file.delete(); - } - - file = new File(mSystemDir, "netstats_uid.bin"); - if (file.exists()) { - mUidRecorder.importLegacyUidLocked(file); - mUidTagRecorder.importLegacyUidLocked(file); - file.delete(); - } - } catch (IOException e) { - Log.wtf(TAG, "problem during legacy upgrade", e); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem during legacy upgrade", e); - } - } - - /** - * Register for a global alert that is delivered through {@link AlertObserver} - * or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has - * been transferred. - */ - private void registerGlobalAlert() { - try { - mNetd.bandwidthSetGlobalAlert(mGlobalAlertBytes); - } catch (IllegalStateException e) { - Log.w(TAG, "problem registering for global alert: " + e); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes)); - } - - @Override - public INetworkStatsSession openSession() { - return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null); - } - - @Override - public INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage) { - return openSessionInternal(flags, callingPackage); - } - - private boolean isRateLimitedForPoll(int callingUid) { - if (callingUid == android.os.Process.SYSTEM_UID) { - return false; - } - - final long lastCallTime; - final long now = SystemClock.elapsedRealtime(); - synchronized (mOpenSessionCallsPerUid) { - int calls = mOpenSessionCallsPerUid.get(callingUid, 0); - mOpenSessionCallsPerUid.put(callingUid, calls + 1); - lastCallTime = mLastStatsSessionPoll; - mLastStatsSessionPoll = now; - } - - return now - lastCallTime < POLL_RATE_LIMIT_MS; - } - - private int restrictFlagsForCaller(int flags) { - // All non-privileged callers are not allowed to turn off POLL_ON_OPEN. - final boolean isPrivileged = PermissionUtils.checkAnyPermissionOf(mContext, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK); - if (!isPrivileged) { - flags |= NetworkStatsManager.FLAG_POLL_ON_OPEN; - } - // Non-system uids are rate limited for POLL_ON_OPEN. - final int callingUid = Binder.getCallingUid(); - flags = isRateLimitedForPoll(callingUid) - ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN) - : flags; - return flags; - } - - private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) { - final int restrictedFlags = restrictFlagsForCaller(flags); - if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN - | NetworkStatsManager.FLAG_POLL_FORCE)) != 0) { - final long ident = Binder.clearCallingIdentity(); - try { - performPoll(FLAG_PERSIST_ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - // return an IBinder which holds strong references to any loaded stats - // for its lifetime; when caller closes only weak references remain. - - return new INetworkStatsSession.Stub() { - private final int mCallingUid = Binder.getCallingUid(); - private final String mCallingPackage = callingPackage; - private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel( - callingPackage); - - private NetworkStatsCollection mUidComplete; - private NetworkStatsCollection mUidTagComplete; - - private NetworkStatsCollection getUidComplete() { - synchronized (mStatsLock) { - if (mUidComplete == null) { - mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); - } - return mUidComplete; - } - } - - private NetworkStatsCollection getUidTagComplete() { - synchronized (mStatsLock) { - if (mUidTagComplete == null) { - mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); - } - return mUidTagComplete; - } - } - - @Override - public int[] getRelevantUids() { - return getUidComplete().getRelevantUids(mAccessLevel); - } - - @Override - public NetworkStats getDeviceSummaryForNetwork( - NetworkTemplate template, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - return internalGetSummaryForNetwork(template, restrictedFlags, start, end, - mAccessLevel, mCallingUid); - } - - @Override - public NetworkStats getSummaryForNetwork( - NetworkTemplate template, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - return internalGetSummaryForNetwork(template, restrictedFlags, start, end, - mAccessLevel, mCallingUid); - } - - // TODO: Remove this after all callers are removed. - @Override - public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - enforceTemplatePermissions(template, callingPackage); - return internalGetHistoryForNetwork(template, restrictedFlags, fields, - mAccessLevel, mCallingUid, Long.MIN_VALUE, Long.MAX_VALUE); - } - - @Override - public NetworkStatsHistory getHistoryIntervalForNetwork(NetworkTemplate template, - int fields, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - // TODO(b/200768422): Redact returned history if the template is location - // sensitive but the caller is not privileged. - return internalGetHistoryForNetwork(template, restrictedFlags, fields, - mAccessLevel, mCallingUid, start, end); - } - - @Override - public NetworkStats getSummaryForAllUid( - NetworkTemplate template, long start, long end, boolean includeTags) { - enforceTemplatePermissions(template, callingPackage); - try { - final NetworkStats stats = getUidComplete() - .getSummary(template, start, end, mAccessLevel, mCallingUid); - if (includeTags) { - final NetworkStats tagStats = getUidTagComplete() - .getSummary(template, start, end, mAccessLevel, mCallingUid); - stats.combineAllValues(tagStats); - } - return stats; - } catch (NullPointerException e) { - throw e; - } - } - - @Override - public NetworkStats getTaggedSummaryForAllUid( - NetworkTemplate template, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - try { - final NetworkStats tagStats = getUidTagComplete() - .getSummary(template, start, end, mAccessLevel, mCallingUid); - return tagStats; - } catch (NullPointerException e) { - throw e; - } - } - - @Override - public NetworkStatsHistory getHistoryForUid( - NetworkTemplate template, int uid, int set, int tag, int fields) { - enforceTemplatePermissions(template, callingPackage); - // NOTE: We don't augment UID-level statistics - if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, null, uid, set, tag, fields, - Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); - } else { - return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, - Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); - } - } - - @Override - public NetworkStatsHistory getHistoryIntervalForUid( - NetworkTemplate template, int uid, int set, int tag, int fields, - long start, long end) { - enforceTemplatePermissions(template, callingPackage); - // TODO(b/200768422): Redact returned history if the template is location - // sensitive but the caller is not privileged. - // NOTE: We don't augment UID-level statistics - if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, null, uid, set, tag, fields, - start, end, mAccessLevel, mCallingUid); - } else if (uid == Binder.getCallingUid()) { - return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, - start, end, mAccessLevel, mCallingUid); - } else { - throw new SecurityException("Calling package " + mCallingPackage - + " cannot access tag information from a different uid"); - } - } - - @Override - public void close() { - mUidComplete = null; - mUidTagComplete = null; - } - }; - } - - private void enforceTemplatePermissions(@NonNull NetworkTemplate template, - @NonNull String callingPackage) { - // For a template with wifi network keys, it is possible for a malicious - // client to track the user locations via querying data usage. Thus, enforce - // fine location permission check. - if (!template.getWifiNetworkKeys().isEmpty()) { - final boolean canAccessFineLocation = mLocationPermissionChecker - .checkCallersLocationPermission(callingPackage, - null /* featureId */, - Binder.getCallingUid(), - false /* coarseForTargetSdkLessThanQ */, - null /* message */); - if (!canAccessFineLocation) { - throw new SecurityException("Access fine location is required when querying" - + " with wifi network keys, make sure the app has the necessary" - + "permissions and the location toggle is on."); - } - } - } - - private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) { - return NetworkStatsAccess.checkAccessLevel( - mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage); - } - - /** - * Find the most relevant {@link SubscriptionPlan} for the given - * {@link NetworkTemplate} and flags. This is typically used to augment - * local measurement results to match a known anchor from the carrier. - */ - private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) { - SubscriptionPlan plan = null; - if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 - && mSettings.getAugmentEnabled()) { - if (LOGD) Log.d(TAG, "Resolving plan for " + template); - final long token = Binder.clearCallingIdentity(); - try { - plan = mContext.getSystemService(NetworkPolicyManager.class) - .getSubscriptionPlan(template); - } finally { - Binder.restoreCallingIdentity(token); - } - if (LOGD) Log.d(TAG, "Resolved to plan " + plan); - } - return plan; - } - - /** - * Return network summary, splicing between DEV and XT stats when - * appropriate. - */ - private NetworkStats internalGetSummaryForNetwork(NetworkTemplate template, int flags, - long start, long end, @NetworkStatsAccess.Level int accessLevel, int callingUid) { - // We've been using pure XT stats long enough that we no longer need to - // splice DEV and XT together. - final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL, - accessLevel, callingUid, start, end); - - final long now = System.currentTimeMillis(); - final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); - - final NetworkStats stats = new NetworkStats(end - start, 1); - stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, - entry.txBytes, entry.txPackets, entry.operations)); - return stats; - } - - /** - * Return network history, splicing between DEV and XT stats when - * appropriate. - */ - private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, - int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid, - long start, long end) { - // We've been using pure XT stats long enough that we no longer need to - // splice DEV and XT together. - final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags); - synchronized (mStatsLock) { - return mXtStatsCached.getHistory(template, augmentPlan, - UID_ALL, SET_ALL, TAG_NONE, fields, start, end, accessLevel, callingUid); - } - } - - private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { - assertSystemReady(); - - return internalGetSummaryForNetwork(template, - NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end, - NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes(); - } - - private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { - assertSystemReady(); - - final NetworkStatsCollection uidComplete; - synchronized (mStatsLock) { - uidComplete = mUidRecorder.getOrLoadCompleteLocked(); - } - return uidComplete.getSummary(template, start, end, NetworkStatsAccess.Level.DEVICE, - android.os.Process.SYSTEM_UID); - } - - @Override - public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException { - if (Binder.getCallingUid() != uid) { - Log.w(TAG, "Snapshots only available for calling UID"); - return new NetworkStats(SystemClock.elapsedRealtime(), 0); - } - - // TODO: switch to data layer stats once kernel exports - // for now, read network layer stats and flatten across all ifaces. - // This function is used to query NeworkStats for calle's uid. The only caller method - // TrafficStats#getDataLayerSnapshotForUid alrady claim no special permission to query - // its own NetworkStats. - final long ident = Binder.clearCallingIdentity(); - final NetworkStats networkLayer; - try { - networkLayer = readNetworkStatsUidDetail(uid, INTERFACES_ALL, TAG_ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - - // splice in operation counts - networkLayer.spliceOperationsFrom(mUidOperations); - - final NetworkStats dataLayer = new NetworkStats( - networkLayer.getElapsedRealtime(), networkLayer.size()); - - NetworkStats.Entry entry = null; - for (int i = 0; i < networkLayer.size(); i++) { - entry = networkLayer.getValues(i, entry); - entry.iface = IFACE_ALL; - dataLayer.combineValues(entry); - } - - return dataLayer; - } - - @Override - public NetworkStats getUidStatsForTransport(int transport) { - PermissionUtils.enforceNetworkStackPermission(mContext); - try { - final String[] relevantIfaces = - transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces; - // TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked - // interfaces, so this is not useful, remove it. - final String[] ifacesToQuery = - mStatsFactory.augmentWithStackedInterfaces(relevantIfaces); - return getNetworkStatsUidDetail(ifacesToQuery); - } catch (RemoteException e) { - Log.wtf(TAG, "Error compiling UID stats", e); - return new NetworkStats(0L, 0); - } - } - - @Override - public String[] getMobileIfaces() { - // TODO (b/192758557): Remove debug log. - if (CollectionUtils.contains(mMobileIfaces, null)) { - throw new NullPointerException( - "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); - } - return mMobileIfaces.clone(); - } - - @Override - public void incrementOperationCount(int uid, int tag, int operationCount) { - if (Binder.getCallingUid() != uid) { - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); - } - - if (operationCount < 0) { - throw new IllegalArgumentException("operation count can only be incremented"); - } - if (tag == TAG_NONE) { - throw new IllegalArgumentException("operation count must have specific tag"); - } - - synchronized (mStatsLock) { - final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT); - mUidOperations.combineValues( - mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount); - mUidOperations.combineValues( - mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount); - } - } - - private void setKernelCounterSet(int uid, int set) { - if (mUidCounterSetMap == null) { - Log.wtf(TAG, "Fail to set UidCounterSet: Null bpf map"); - return; - } - - if (set == SET_DEFAULT) { - try { - mUidCounterSetMap.deleteEntry(new U32(uid)); - } catch (ErrnoException e) { - Log.w(TAG, "UidCounterSetMap.deleteEntry(" + uid + ") failed with errno: " + e); - } - return; - } - - try { - mUidCounterSetMap.updateEntry(new U32(uid), new U8((short) set)); - } catch (ErrnoException e) { - Log.w(TAG, "UidCounterSetMap.updateEntry(" + uid + ", " + set - + ") failed with errno: " + e); - } - } - - @VisibleForTesting - public void noteUidForeground(int uid, boolean uidForeground) { - PermissionUtils.enforceNetworkStackPermission(mContext); - synchronized (mStatsLock) { - final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; - final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT); - if (oldSet != set) { - mActiveUidCounterSet.put(uid, set); - setKernelCounterSet(uid, set); - } - } - } - - /** - * Notify {@code NetworkStatsService} about network status changed. - */ - public void notifyNetworkStatus( - @NonNull Network[] defaultNetworks, - @NonNull NetworkStateSnapshot[] networkStates, - @Nullable String activeIface, - @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) { - PermissionUtils.enforceNetworkStackPermission(mContext); - - final long token = Binder.clearCallingIdentity(); - try { - handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface); - } finally { - Binder.restoreCallingIdentity(token); - } - - // Update the VPN underlying interfaces only after the poll is made and tun data has been - // migrated. Otherwise the migration would use the new interfaces instead of the ones that - // were current when the polled data was transferred. - mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos); - } - - @Override - public void forceUpdate() { - PermissionUtils.enforceNetworkStackPermission(mContext); - - final long token = Binder.clearCallingIdentity(); - try { - performPoll(FLAG_PERSIST_ALL); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** Advise persistence threshold; may be overridden internally. */ - public void advisePersistThreshold(long thresholdBytes) { - PermissionUtils.enforceNetworkStackPermission(mContext); - // clamp threshold into safe range - mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes, - 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); - if (LOGV) { - Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to " - + mPersistThreshold); - } - - final long oldGlobalAlertBytes = mGlobalAlertBytes; - - // update and persist if beyond new thresholds - final long currentTime = mClock.millis(); - synchronized (mStatsLock) { - if (!mSystemReady) return; - - updatePersistThresholdsLocked(); - - mDevRecorder.maybePersistLocked(currentTime); - mXtRecorder.maybePersistLocked(currentTime); - mUidRecorder.maybePersistLocked(currentTime); - mUidTagRecorder.maybePersistLocked(currentTime); - } - - if (oldGlobalAlertBytes != mGlobalAlertBytes) { - registerGlobalAlert(); - } - } - - @Override - public DataUsageRequest registerUsageCallback(@NonNull String callingPackage, - @NonNull DataUsageRequest request, @NonNull IUsageCallback callback) { - Objects.requireNonNull(callingPackage, "calling package is null"); - Objects.requireNonNull(request, "DataUsageRequest is null"); - Objects.requireNonNull(request.template, "NetworkTemplate is null"); - Objects.requireNonNull(callback, "callback is null"); - - int callingUid = Binder.getCallingUid(); - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage); - DataUsageRequest normalizedRequest; - final long token = Binder.clearCallingIdentity(); - try { - normalizedRequest = mStatsObservers.register(mContext, - request, callback, callingUid, accessLevel); - } finally { - Binder.restoreCallingIdentity(token); - } - - // Create baseline stats - mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL)); - - return normalizedRequest; - } - - @Override - public void unregisterUsageRequest(DataUsageRequest request) { - Objects.requireNonNull(request, "DataUsageRequest is null"); - - int callingUid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - mStatsObservers.unregister(request, callingUid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public long getUidStats(int uid, int type) { - final int callingUid = Binder.getCallingUid(); - if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) { - return UNSUPPORTED; - } - return nativeGetUidStat(uid, type); - } - - @Override - public long getIfaceStats(@NonNull String iface, int type) { - Objects.requireNonNull(iface); - long nativeIfaceStats = nativeGetIfaceStat(iface, type); - if (nativeIfaceStats == -1) { - return nativeIfaceStats; - } else { - // When tethering offload is in use, nativeIfaceStats does not contain usage from - // offload, add it back here. Note that the included statistics might be stale - // since polling newest stats from hardware might impact system health and not - // suitable for TrafficStats API use cases. - return nativeIfaceStats + getProviderIfaceStats(iface, type); - } - } - - @Override - public long getTotalStats(int type) { - long nativeTotalStats = nativeGetTotalStat(type); - if (nativeTotalStats == -1) { - return nativeTotalStats; - } else { - // Refer to comment in getIfaceStats - return nativeTotalStats + getProviderIfaceStats(IFACE_ALL, type); - } - } - - private long getProviderIfaceStats(@Nullable String iface, int type) { - final NetworkStats providerSnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); - final HashSet<String> limitIfaces; - if (iface == IFACE_ALL) { - limitIfaces = null; - } else { - limitIfaces = new HashSet<>(); - limitIfaces.add(iface); - } - final NetworkStats.Entry entry = providerSnapshot.getTotal(null, limitIfaces); - switch (type) { - case TrafficStats.TYPE_RX_BYTES: - return entry.rxBytes; - case TrafficStats.TYPE_RX_PACKETS: - return entry.rxPackets; - case TrafficStats.TYPE_TX_BYTES: - return entry.txBytes; - case TrafficStats.TYPE_TX_PACKETS: - return entry.txPackets; - default: - return 0; - } - } - - /** - * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to - * reflect current {@link #mPersistThreshold} value. Always defers to - * {@link Global} values when defined. - */ - @GuardedBy("mStatsLock") - private void updatePersistThresholdsLocked() { - mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold)); - mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold)); - mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold)); - mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold)); - mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); - } - - /** - * Listener that watches for {@link TetheringManager} to claim interface pairs. - */ - private final TetheringManager.TetheringEventCallback mTetherListener = - new TetheringManager.TetheringEventCallback() { - @Override - public void onUpstreamChanged(@Nullable Network network) { - performPoll(FLAG_PERSIST_NETWORK); - } - }; - - private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // on background handler thread, and verified UPDATE_DEVICE_STATS - // permission above. - performPoll(FLAG_PERSIST_ALL); - - // verify that we're watching global alert - registerGlobalAlert(); - } - }; - - private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // on background handler thread, and UID_REMOVED is protected - // broadcast. - - final int uid = intent.getIntExtra(EXTRA_UID, -1); - if (uid == -1) return; - - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - removeUidsLocked(uid); - } finally { - mWakeLock.release(); - } - } - } - }; - - private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // On background handler thread, and USER_REMOVED is protected - // broadcast. - - final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); - if (userHandle == null) return; - - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - removeUserLocked(userHandle); - } finally { - mWakeLock.release(); - } - } - } - }; - - private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // SHUTDOWN is protected broadcast. - synchronized (mStatsLock) { - shutdownLocked(); - } - } - }; - - /** - * Handle collapsed RAT type changed event. - */ - @VisibleForTesting - public void handleOnCollapsedRatTypeChanged() { - // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS); - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay()); - } - - private void handleNotifyNetworkStatus( - Network[] defaultNetworks, - NetworkStateSnapshot[] snapshots, - String activeIface) { - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - mActiveIface = activeIface; - handleNotifyNetworkStatusLocked(defaultNetworks, snapshots); - } finally { - mWakeLock.release(); - } - } - } - - /** - * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to - * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, - * they are combined under a single {@link NetworkIdentitySet}. - */ - @GuardedBy("mStatsLock") - private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks, - @NonNull NetworkStateSnapshot[] snapshots) { - if (!mSystemReady) return; - if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()"); - - // take one last stats snapshot before updating iface mapping. this - // isn't perfect, since the kernel may already be counting traffic from - // the updated network. - - // poll, but only persist network stats to keep codepath fast. UID stats - // will be persisted during next alarm poll event. - performPollLocked(FLAG_PERSIST_NETWORK); - - // Rebuild active interfaces based on connected networks - mActiveIfaces.clear(); - mActiveUidIfaces.clear(); - // Update the list of default networks. - mDefaultNetworks = defaultNetworks; - - mLastNetworkStateSnapshots = snapshots; - - final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); - final ArraySet<String> mobileIfaces = new ArraySet<>(); - final ArraySet<String> wifiIfaces = new ArraySet<>(); - for (NetworkStateSnapshot snapshot : snapshots) { - final int displayTransport = - getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); - final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); - final boolean isWifi = (NetworkCapabilities.TRANSPORT_WIFI == displayTransport); - final boolean isDefault = CollectionUtils.contains( - mDefaultNetworks, snapshot.getNetwork()); - final int ratType = combineSubtypeEnabled ? NetworkTemplate.NETWORK_TYPE_ALL - : getRatTypeForStateSnapshot(snapshot); - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, - isDefault, ratType); - - // Traffic occurring on the base interface is always counted for - // both total usage and UID details. - final String baseIface = snapshot.getLinkProperties().getInterfaceName(); - if (baseIface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); - - // Build a separate virtual interface for VT (Video Telephony) data usage. - // Only do this when IMS is not metered, but VT is metered. - // If IMS is metered, then the IMS network usage has already included VT usage. - // VT is considered always metered in framework's layer. If VT is not metered - // per carrier's policy, modem will report 0 usage for VT calls. - if (snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) { - - // Copy the identify from IMS one but mark it as metered. - NetworkIdentity vtIdent = new NetworkIdentity.Builder() - .setType(ident.getType()) - .setRatType(ident.getRatType()) - .setSubscriberId(ident.getSubscriberId()) - .setWifiNetworkKey(ident.getWifiNetworkKey()) - .setRoaming(ident.isRoaming()).setMetered(true) - .setDefaultNetwork(true) - .setOemManaged(ident.getOemManaged()) - .setSubId(ident.getSubId()).build(); - final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); - findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); - } - - if (isMobile) { - mobileIfaces.add(baseIface); - } - if (isWifi) { - wifiIfaces.add(baseIface); - } - } - - // Traffic occurring on stacked interfaces is usually clatd. - // - // UID stats are always counted on the stacked interface and never on the base - // interface, because the packets on the base interface do not actually match - // application sockets (they're not IPv4) and thus the app uid is not known. - // For receive this is obvious: packets must be translated from IPv6 to IPv4 - // before the application socket can be found. - // For transmit: either they go through the clat daemon which by virtue of going - // through userspace strips the original socket association during the IPv4 to - // IPv6 translation process, or they are offloaded by eBPF, which doesn't: - // However, on an ebpf device the accounting is done in cgroup ebpf hooks, - // which don't trigger again post ebpf translation. - // (as such stats accounted to the clat uid are ignored) - // - // Interface stats are more complicated. - // - // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus - // *all* statistics are collected by iptables on the stacked v4-* interface. - // - // Additionally for ingress all packets bound for the clat IPv6 address are dropped - // in ip6tables raw prerouting and thus even non-offloaded packets are only - // accounted for on the stacked interface. - // - // For egress, packets subject to eBPF offload never appear on the base interface - // and only appear on the stacked interface. Thus to ensure packets increment - // interface stats, we must collate data from stacked interfaces. For xt_qtaguid - // (or non eBPF offloaded) TX they would appear on both, however egress interface - // accounting is explicitly bypassed for traffic from the clat uid. - // - // TODO: This code might be combined to above code. - for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) { - // baseIface has been handled, so ignore it. - if (TextUtils.equals(baseIface, iface)) continue; - if (iface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident); - if (isMobile) { - mobileIfaces.add(iface); - } - if (isWifi) { - wifiIfaces.add(iface); - } - - mStatsFactory.noteStackedIface(iface, baseIface); - } - } - } - - mMobileIfaces = mobileIfaces.toArray(new String[0]); - mWifiIfaces = wifiIfaces.toArray(new String[0]); - // TODO (b/192758557): Remove debug log. - if (CollectionUtils.contains(mMobileIfaces, null)) { - throw new NullPointerException( - "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); - } - if (CollectionUtils.contains(mWifiIfaces, null)) { - throw new NullPointerException( - "null element in mWifiIfaces: " + Arrays.toString(mWifiIfaces)); - } - } - - private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { - if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR"); - } - - final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier(); - if (spec instanceof TelephonyNetworkSpecifier) { - return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); - } else { - Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier"); - return INVALID_SUBSCRIPTION_ID; - } - } - - /** - * For networks with {@code TRANSPORT_CELLULAR}, get ratType that was obtained through - * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different - * transport types do not actually fill this value. - */ - private int getRatTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { - if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - return 0; - } - - return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId()); - } - - private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet( - ArrayMap<K, NetworkIdentitySet> map, K key) { - NetworkIdentitySet ident = map.get(key); - if (ident == null) { - ident = new NetworkIdentitySet(); - map.put(key, ident); - } - return ident; - } - - @GuardedBy("mStatsLock") - private void recordSnapshotLocked(long currentTime) throws RemoteException { - // snapshot and record current counters; read UID stats first to - // avoid over counting dev stats. - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotUid"); - final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt"); - final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev"); - final NetworkStats devSnapshot = readNetworkStatsSummaryDev(); - Trace.traceEnd(TRACE_TAG_NETWORK); - - // Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data - // from stats providers that isn't already counted by dev and XT stats. - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider"); - final NetworkStats providersnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); - Trace.traceEnd(TRACE_TAG_NETWORK); - xtSnapshot.combineAllValues(providersnapshot); - devSnapshot.combineAllValues(providersnapshot); - - // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic - // can't be reattributed to responsible apps. - Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); - mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt"); - mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - - // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - - // We need to make copies of member fields that are sent to the observer to avoid - // a race condition between the service handler thread and the observer's - mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), - new ArrayMap<>(mActiveUidIfaces), currentTime); - } - - /** - * Bootstrap initial stats snapshot, usually during {@link #systemReady()} - * so we have baseline values without double-counting. - */ - @GuardedBy("mStatsLock") - private void bootstrapStatsLocked() { - final long currentTime = mClock.millis(); - - try { - recordSnapshotLocked(currentTime); - } catch (IllegalStateException e) { - Log.w(TAG, "problem reading network stats: " + e); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - } - - private void performPoll(int flags) { - synchronized (mStatsLock) { - mWakeLock.acquire(); - - try { - performPollLocked(flags); - } finally { - mWakeLock.release(); - } - } - } - - /** - * Periodic poll operation, reading current statistics and recording into - * {@link NetworkStatsHistory}. - */ - @GuardedBy("mStatsLock") - private void performPollLocked(int flags) { - if (!mSystemReady) return; - if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); - Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked"); - - final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; - final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; - final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; - - performPollFromProvidersLocked(); - - // TODO: consider marking "untrusted" times in historical stats - final long currentTime = mClock.millis(); - - try { - recordSnapshotLocked(currentTime); - } catch (IllegalStateException e) { - Log.wtf(TAG, "problem reading network stats", e); - return; - } catch (RemoteException e) { - // ignored; service lives in system_server - return; - } - - // persist any pending data depending on requested flags - Trace.traceBegin(TRACE_TAG_NETWORK, "[persisting]"); - if (persistForce) { - mDevRecorder.forcePersistLocked(currentTime); - mXtRecorder.forcePersistLocked(currentTime); - mUidRecorder.forcePersistLocked(currentTime); - mUidTagRecorder.forcePersistLocked(currentTime); - } else { - if (persistNetwork) { - mDevRecorder.maybePersistLocked(currentTime); - mXtRecorder.maybePersistLocked(currentTime); - } - if (persistUid) { - mUidRecorder.maybePersistLocked(currentTime); - mUidTagRecorder.maybePersistLocked(currentTime); - } - } - Trace.traceEnd(TRACE_TAG_NETWORK); - - if (mSettings.getSampleEnabled()) { - // sample stats after each full poll - performSampleLocked(); - } - - // finally, dispatch updated event to any listeners - mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED)); - - Trace.traceEnd(TRACE_TAG_NETWORK); - } - - @GuardedBy("mStatsLock") - private void performPollFromProvidersLocked() { - // Request asynchronous stats update from all providers for next poll. And wait a bit of - // time to allow providers report-in given that normally binder call should be fast. Note - // that size of list might be changed because addition/removing at the same time. For - // addition, the stats of the missed provider can only be collected in next poll; - // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS - // once that happened. - // TODO: request with a valid token. - Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); - final int registeredCallbackCount = mStatsProviderCbList.size(); - mStatsProviderSem.drainPermits(); - invokeForAllStatsProviderCallbacks( - (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); - try { - mStatsProviderSem.tryAcquire(registeredCallbackCount, - MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - // Strictly speaking it's possible a provider happened to deliver between the timeout - // and the log, and that doesn't matter too much as this is just a debug log. - Log.d(TAG, "requestStatsUpdate - providers responded " - + mStatsProviderSem.availablePermits() - + "/" + registeredCallbackCount + " : " + e); - } - Trace.traceEnd(TRACE_TAG_NETWORK); - } - - /** - * Sample recent statistics summary into {@link EventLog}. - */ - @GuardedBy("mStatsLock") - private void performSampleLocked() { - // TODO: migrate trustedtime fixes to separate binary log events - final long currentTime = mClock.millis(); - - NetworkTemplate template; - NetworkStats.Entry devTotal; - NetworkStats.Entry xtTotal; - NetworkStats.Entry uidTotal; - - // collect mobile sample - template = buildTemplateMobileWildcard(); - devTotal = mDevRecorder.getTotalSinceBootLocked(template); - xtTotal = mXtRecorder.getTotalSinceBootLocked(template); - uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - - EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, - devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, - xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, - uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - currentTime); - - // collect wifi sample - template = buildTemplateWifiWildcard(); - devTotal = mDevRecorder.getTotalSinceBootLocked(template); - xtTotal = mXtRecorder.getTotalSinceBootLocked(template); - uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - - EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, - devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, - xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, - uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - currentTime); - } - - // deleteKernelTagData can ignore ENOENT; otherwise we should log an error - private void logErrorIfNotErrNoent(final ErrnoException e, final String msg) { - if (e.errno != ENOENT) Log.e(TAG, msg, e); - } - - private <K extends StatsMapKey, V extends StatsMapValue> void deleteStatsMapTagData( - IBpfMap<K, V> statsMap, int uid) { - try { - statsMap.forEach((key, value) -> { - if (key.uid == uid) { - try { - statsMap.deleteEntry(key); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete data(uid = " + key.uid + ")"); - } - } - }); - } catch (ErrnoException e) { - Log.e(TAG, "FAILED to delete tag data from stats map", e); - } - } - - /** - * Deletes uid tag data from CookieTagMap, StatsMapA, StatsMapB, and UidStatsMap - * @param uid - */ - private void deleteKernelTagData(int uid) { - try { - mCookieTagMap.forEach((key, value) -> { - // If SkDestroyListener deletes the socket tag while this code is running, - // forEach will either restart iteration from the beginning or return null, - // depending on when the deletion happens. - // If it returns null, continue iteration to delete the data and in fact it would - // just iterate from first key because BpfMap#getNextKey would return first key - // if the current key is not exist. - if (value != null && value.uid == uid) { - try { - mCookieTagMap.deleteEntry(key); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete data(cookie = " + key + ")"); - } - } - }); - } catch (ErrnoException e) { - Log.e(TAG, "Failed to delete tag data from cookie tag map", e); - } - - deleteStatsMapTagData(mStatsMapA, uid); - deleteStatsMapTagData(mStatsMapB, uid); - - try { - mUidCounterSetMap.deleteEntry(new U32(uid)); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete tag data from uid counter set map"); - } - - try { - mAppUidStatsMap.deleteEntry(new UidStatsMapKey(uid)); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete tag data from app uid stats map"); - } - } - - /** - * Clean up {@link #mUidRecorder} after UID is removed. - */ - @GuardedBy("mStatsLock") - private void removeUidsLocked(int... uids) { - if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); - - // Perform one last poll before removing - performPollLocked(FLAG_PERSIST_ALL); - - mUidRecorder.removeUidsLocked(uids); - mUidTagRecorder.removeUidsLocked(uids); - - // Clear kernel stats associated with UID - for (int uid : uids) { - deleteKernelTagData(uid); - } - } - - /** - * Clean up {@link #mUidRecorder} after user is removed. - */ - @GuardedBy("mStatsLock") - private void removeUserLocked(@NonNull UserHandle userHandle) { - if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle); - - // Build list of UIDs that we should clean up - final ArrayList<Integer> uids = new ArrayList<>(); - final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications( - PackageManager.MATCH_ANY_USER - | PackageManager.MATCH_DISABLED_COMPONENTS); - for (ApplicationInfo app : apps) { - final int uid = userHandle.getUid(app.uid); - uids.add(uid); - } - - removeUidsLocked(CollectionUtils.toIntArray(uids)); - } - - /** - * Set the warning and limit to all registered custom network stats providers. - * Note that invocation of any interface will be sent to all providers. - */ - public void setStatsProviderWarningAndLimitAsync( - @NonNull String iface, long warning, long limit) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (LOGV) { - Log.v(TAG, "setStatsProviderWarningAndLimitAsync(" - + iface + "," + warning + "," + limit + ")"); - } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, - warning, limit)); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) { - if (!PermissionUtils.checkDumpPermission(mContext, TAG, rawWriter)) return; - - long duration = DateUtils.DAY_IN_MILLIS; - final HashSet<String> argSet = new HashSet<String>(); - for (String arg : args) { - argSet.add(arg); - - if (arg.startsWith("--duration=")) { - try { - duration = Long.parseLong(arg.substring(11)); - } catch (NumberFormatException ignored) { - } - } - } - - // usage: dumpsys netstats --full --uid --tag --poll --checkin - final boolean poll = argSet.contains("--poll") || argSet.contains("poll"); - final boolean checkin = argSet.contains("--checkin"); - final boolean fullHistory = argSet.contains("--full") || argSet.contains("full"); - final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail"); - final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail"); - - final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); - - synchronized (mStatsLock) { - if (args.length > 0 && "--proto".equals(args[0])) { - // In this case ignore all other arguments. - dumpProtoLocked(fd); - return; - } - - if (poll) { - performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); - pw.println("Forced poll"); - return; - } - - if (checkin) { - final long end = System.currentTimeMillis(); - final long start = end - duration; - - pw.print("v1,"); - pw.print(start / SECOND_IN_MILLIS); pw.print(','); - pw.print(end / SECOND_IN_MILLIS); pw.println(); - - pw.println("xt"); - mXtRecorder.dumpCheckin(rawWriter, start, end); - - if (includeUid) { - pw.println("uid"); - mUidRecorder.dumpCheckin(rawWriter, start, end); - } - if (includeTag) { - pw.println("tag"); - mUidTagRecorder.dumpCheckin(rawWriter, start, end); - } - return; - } - - pw.println("Configs:"); - pw.increaseIndent(); - pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); - pw.println(); - pw.decreaseIndent(); - - pw.println("Active interfaces:"); - pw.increaseIndent(); - for (int i = 0; i < mActiveIfaces.size(); i++) { - pw.print("iface", mActiveIfaces.keyAt(i)); - pw.print("ident", mActiveIfaces.valueAt(i)); - pw.println(); - } - pw.decreaseIndent(); - - pw.println("Active UID interfaces:"); - pw.increaseIndent(); - for (int i = 0; i < mActiveUidIfaces.size(); i++) { - pw.print("iface", mActiveUidIfaces.keyAt(i)); - pw.print("ident", mActiveUidIfaces.valueAt(i)); - pw.println(); - } - pw.decreaseIndent(); - - // Get the top openSession callers - final SparseIntArray calls; - synchronized (mOpenSessionCallsPerUid) { - calls = mOpenSessionCallsPerUid.clone(); - } - - final int N = calls.size(); - final long[] values = new long[N]; - for (int j = 0; j < N; j++) { - values[j] = ((long) calls.valueAt(j) << 32) | calls.keyAt(j); - } - Arrays.sort(values); - - pw.println("Top openSession callers (uid=count):"); - pw.increaseIndent(); - final int end = Math.max(0, N - DUMP_STATS_SESSION_COUNT); - for (int j = N - 1; j >= end; j--) { - final int uid = (int) (values[j] & 0xffffffff); - final int count = (int) (values[j] >> 32); - pw.print(uid); pw.print("="); pw.println(count); - } - pw.decreaseIndent(); - pw.println(); - - pw.println("Stats Providers:"); - pw.increaseIndent(); - invokeForAllStatsProviderCallbacks((cb) -> { - pw.println(cb.mTag + " Xt:"); - pw.increaseIndent(); - pw.print(cb.getCachedStats(STATS_PER_IFACE).toString()); - pw.decreaseIndent(); - if (includeUid) { - pw.println(cb.mTag + " Uid:"); - pw.increaseIndent(); - pw.print(cb.getCachedStats(STATS_PER_UID).toString()); - pw.decreaseIndent(); - } - }); - pw.decreaseIndent(); - - pw.println("Dev stats:"); - pw.increaseIndent(); - mDevRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - - pw.println("Xt stats:"); - pw.increaseIndent(); - mXtRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - - if (includeUid) { - pw.println("UID stats:"); - pw.increaseIndent(); - mUidRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - } - - if (includeTag) { - pw.println("UID tag stats:"); - pw.increaseIndent(); - mUidTagRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - } - } - } - - @GuardedBy("mStatsLock") - private void dumpProtoLocked(FileDescriptor fd) { - final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd)); - - // TODO Right now it writes all history. Should it limit to the "since-boot" log? - - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, - mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, - mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); - mUidTagRecorder.dumpDebugLocked(proto, - NetworkStatsServiceDumpProto.UID_TAG_STATS); - - proto.flush(); - } - - private static void dumpInterfaces(ProtoOutputStream proto, long tag, - ArrayMap<String, NetworkIdentitySet> ifaces) { - for (int i = 0; i < ifaces.size(); i++) { - final long start = proto.start(tag); - - proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); - - proto.end(start); - } - } - - private NetworkStats readNetworkStatsSummaryDev() { - try { - return mStatsFactory.readNetworkStatsSummaryDev(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private NetworkStats readNetworkStatsSummaryXt() { - try { - return mStatsFactory.readNetworkStatsSummaryXt(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private NetworkStats readNetworkStatsUidDetail(int uid, String[] ifaces, int tag) { - try { - return mStatsFactory.readNetworkStatsDetail(uid, ifaces, tag); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - /** - * Return snapshot of current UID statistics, including any - * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} - * values. - * - * @param ifaces A list of interfaces the stats should be restricted to, or - * {@link NetworkStats#INTERFACES_ALL}. - */ - private NetworkStats getNetworkStatsUidDetail(String[] ifaces) - throws RemoteException { - final NetworkStats uidSnapshot = readNetworkStatsUidDetail(UID_ALL, ifaces, TAG_ALL); - - // fold tethering stats and operations into uid snapshot - final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); - tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); - uidSnapshot.combineAllValues(tetherSnapshot); - - // get a stale copy of uid stats snapshot provided by providers. - final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); - providerStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); - uidSnapshot.combineAllValues(providerStats); - - uidSnapshot.combineAllValues(mUidOperations); - - return uidSnapshot; - } - - /** - * Return snapshot of current non-offloaded tethering statistics. Will return empty - * {@link NetworkStats} if any problems are encountered, or queried by {@code STATS_PER_IFACE} - * since it is already included by {@link #nativeGetIfaceStat}. - * See {@code OffloadTetheringStatsProvider} for offloaded tethering stats. - */ - // TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded - // tethering stats. - private @NonNull NetworkStats getNetworkStatsTethering(int how) throws RemoteException { - // We only need to return per-UID stats. Per-device stats are already counted by - // interface counters. - if (how != STATS_PER_UID) { - return new NetworkStats(SystemClock.elapsedRealtime(), 0); - } - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - try { - final TetherStatsParcel[] tetherStatsParcels = mNetd.tetherGetStats(); - for (TetherStatsParcel tetherStats : tetherStatsParcels) { - try { - stats.combineValues(new NetworkStats.Entry(tetherStats.iface, UID_TETHERING, - SET_DEFAULT, TAG_NONE, tetherStats.rxBytes, tetherStats.rxPackets, - tetherStats.txBytes, tetherStats.txPackets, 0L)); - } catch (ArrayIndexOutOfBoundsException e) { - throw new IllegalStateException("invalid tethering stats " + e); - } - } - } catch (IllegalStateException e) { - Log.wtf(TAG, "problem reading network stats", e); - } - return stats; - } - - // TODO: It is copied from ConnectivityService, consider refactor these check permission - // functions to a proper util. - private boolean checkAnyPermissionOf(String... permissions) { - for (String permission : permissions) { - if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { - return true; - } - } - return false; - } - - private void enforceAnyPermissionOf(String... permissions) { - if (!checkAnyPermissionOf(permissions)) { - throw new SecurityException("Requires one of the following permissions: " - + String.join(", ", permissions) + "."); - } - } - - /** - * Registers a custom provider of {@link android.net.NetworkStats} to combine the network - * statistics that cannot be seen by the kernel to system. To unregister, invoke the - * {@code unregister()} of the returned callback. - * - * @param tag a human readable identifier of the custom network stats provider. - * @param provider the {@link INetworkStatsProvider} binder corresponding to the - * {@link NetworkStatsProvider} to be registered. - * - * @return a {@link INetworkStatsProviderCallback} binder - * interface, which can be used to report events to the system. - */ - public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( - @NonNull String tag, @NonNull INetworkStatsProvider provider) { - enforceAnyPermissionOf(NETWORK_STATS_PROVIDER, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); - Objects.requireNonNull(provider, "provider is null"); - Objects.requireNonNull(tag, "tag is null"); - final NetworkPolicyManager netPolicyManager = mContext - .getSystemService(NetworkPolicyManager.class); - try { - NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( - tag, provider, mStatsProviderSem, mAlertObserver, - mStatsProviderCbList, netPolicyManager); - mStatsProviderCbList.add(callback); - Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" - + getCallingUid() + "/" + getCallingPid()); - return callback; - } catch (RemoteException e) { - Log.e(TAG, "registerNetworkStatsProvider failed", e); - } - return null; - } - - // Collect stats from local cache of providers. - private @NonNull NetworkStats getNetworkStatsFromProviders(int how) { - final NetworkStats ret = new NetworkStats(0L, 0); - invokeForAllStatsProviderCallbacks((cb) -> ret.combineAllValues(cb.getCachedStats(how))); - return ret; - } - - @FunctionalInterface - private interface ThrowingConsumer<S, T extends Throwable> { - void accept(S s) throws T; - } - - private void invokeForAllStatsProviderCallbacks( - @NonNull ThrowingConsumer<NetworkStatsProviderCallbackImpl, RemoteException> task) { - for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) { - try { - task.accept(cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); - } - } - } - - private static class NetworkStatsProviderCallbackImpl extends INetworkStatsProviderCallback.Stub - implements IBinder.DeathRecipient { - @NonNull final String mTag; - - @NonNull final INetworkStatsProvider mProvider; - @NonNull private final Semaphore mSemaphore; - @NonNull final AlertObserver mAlertObserver; - @NonNull final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList; - @NonNull final NetworkPolicyManager mNetworkPolicyManager; - - @NonNull private final Object mProviderStatsLock = new Object(); - - @GuardedBy("mProviderStatsLock") - // Track STATS_PER_IFACE and STATS_PER_UID separately. - private final NetworkStats mIfaceStats = new NetworkStats(0L, 0); - @GuardedBy("mProviderStatsLock") - private final NetworkStats mUidStats = new NetworkStats(0L, 0); - - NetworkStatsProviderCallbackImpl( - @NonNull String tag, @NonNull INetworkStatsProvider provider, - @NonNull Semaphore semaphore, - @NonNull AlertObserver alertObserver, - @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList, - @NonNull NetworkPolicyManager networkPolicyManager) - throws RemoteException { - mTag = tag; - mProvider = provider; - mProvider.asBinder().linkToDeath(this, 0); - mSemaphore = semaphore; - mAlertObserver = alertObserver; - mStatsProviderCbList = cbList; - mNetworkPolicyManager = networkPolicyManager; - } - - @NonNull - public NetworkStats getCachedStats(int how) { - synchronized (mProviderStatsLock) { - NetworkStats stats; - switch (how) { - case STATS_PER_IFACE: - stats = mIfaceStats; - break; - case STATS_PER_UID: - stats = mUidStats; - break; - default: - throw new IllegalArgumentException("Invalid type: " + how); - } - // Callers might be able to mutate the returned object. Return a defensive copy - // instead of local reference. - return stats.clone(); - } - } - - @Override - public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats, - @Nullable NetworkStats uidStats) { - // TODO: 1. Use token to map ifaces to correct NetworkIdentity. - // 2. Store the difference and store it directly to the recorder. - synchronized (mProviderStatsLock) { - if (ifaceStats != null) mIfaceStats.combineAllValues(ifaceStats); - if (uidStats != null) mUidStats.combineAllValues(uidStats); - } - mSemaphore.release(); - } - - @Override - public void notifyAlertReached() throws RemoteException { - // This binder object can only have been obtained by a process that holds - // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required. - BinderUtils.withCleanCallingIdentity(() -> - mAlertObserver.onQuotaLimitReached(LIMIT_GLOBAL_ALERT, null /* unused */)); - } - - @Override - public void notifyWarningReached() { - Log.d(TAG, mTag + ": notifyWarningReached"); - BinderUtils.withCleanCallingIdentity(() -> - mNetworkPolicyManager.notifyStatsProviderWarningReached()); - } - - @Override - public void notifyLimitReached() { - Log.d(TAG, mTag + ": notifyLimitReached"); - BinderUtils.withCleanCallingIdentity(() -> - mNetworkPolicyManager.notifyStatsProviderLimitReached()); - } - - @Override - public void binderDied() { - Log.d(TAG, mTag + ": binderDied"); - mStatsProviderCbList.remove(this); - } - - @Override - public void unregister() { - Log.d(TAG, mTag + ": unregister"); - mStatsProviderCbList.remove(this); - } - - } - - private void assertSystemReady() { - if (!mSystemReady) { - throw new IllegalStateException("System not ready"); - } - } - - private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> { - @Override - public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right, - int rightIndex, String cookie) { - Log.w(TAG, "Found non-monotonic values; saving to dropbox"); - - // record error for debugging - final StringBuilder builder = new StringBuilder(); - builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex - + "] - right[" + rightIndex + "]\n"); - builder.append("left=").append(left).append('\n'); - builder.append("right=").append(right).append('\n'); - - mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, - builder.toString()); - } - - @Override - public void foundNonMonotonic( - NetworkStats stats, int statsIndex, String cookie) { - Log.w(TAG, "Found non-monotonic values; saving to dropbox"); - - final StringBuilder builder = new StringBuilder(); - builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n"); - builder.append("stats=").append(stats).append('\n'); - - mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, - builder.toString()); - } - } - - /** - * Default external settings that read from - * {@link android.provider.Settings.Global}. - */ - private static class DefaultNetworkStatsSettings implements NetworkStatsSettings { - DefaultNetworkStatsSettings() {} - - @Override - public long getPollInterval() { - return 30 * MINUTE_IN_MILLIS; - } - @Override - public long getPollDelay() { - return DEFAULT_PERFORM_POLL_DELAY_MS; - } - @Override - public long getGlobalAlertBytes(long def) { - return def; - } - @Override - public boolean getSampleEnabled() { - return true; - } - @Override - public boolean getAugmentEnabled() { - return true; - } - @Override - public boolean getCombineSubtypeEnabled() { - return false; - } - @Override - public Config getDevConfig() { - return new Config(HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); - } - @Override - public Config getXtConfig() { - return getDevConfig(); - } - @Override - public Config getUidConfig() { - return new Config(2 * HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); - } - @Override - public Config getUidTagConfig() { - return new Config(2 * HOUR_IN_MILLIS, 5 * DAY_IN_MILLIS, 15 * DAY_IN_MILLIS); - } - @Override - public long getDevPersistBytes(long def) { - return def; - } - @Override - public long getXtPersistBytes(long def) { - return def; - } - @Override - public long getUidPersistBytes(long def) { - return def; - } - @Override - public long getUidTagPersistBytes(long def) { - return def; - } - } - - private static native long nativeGetTotalStat(int type); - private static native long nativeGetIfaceStat(String iface, int type); - private static native long nativeGetUidStat(int uid, int type); -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java deleted file mode 100644 index 65ccd2007299..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA; -import static android.app.usage.NetworkStatsManager.getCollapsedRatType; -import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED; -import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA; -import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; - -import android.annotation.NonNull; -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyCallback; -import android.telephony.TelephonyDisplayInfo; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; - -/** - * Helper class that watches for events that are triggered per subscription. - */ -@TargetApi(Build.VERSION_CODES.TIRAMISU) -public class NetworkStatsSubscriptionsMonitor extends - SubscriptionManager.OnSubscriptionsChangedListener { - - /** - * Interface that this monitor uses to delegate event handling to NetworkStatsService. - */ - public interface Delegate { - /** - * Notify that the collapsed RAT type has been changed for any subscription. The method - * will also be triggered for any existing sub when start and stop monitoring. - * - * @param subscriberId IMSI of the subscription. - * @param collapsedRatType collapsed RAT type. - * @see android.app.usage.NetworkStatsManager#getCollapsedRatType(int). - */ - void onCollapsedRatTypeChanged(@NonNull String subscriberId, int collapsedRatType); - } - private final Delegate mDelegate; - - /** - * Receivers that watches for {@link TelephonyDisplayInfo} changes for each subscription, to - * monitor the transitioning between Radio Access Technology(RAT) types for each sub. - */ - @NonNull - private final CopyOnWriteArrayList<RatTypeListener> mRatListeners = - new CopyOnWriteArrayList<>(); - - @NonNull - private final SubscriptionManager mSubscriptionManager; - @NonNull - private final TelephonyManager mTeleManager; - - @NonNull - private final Executor mExecutor; - - NetworkStatsSubscriptionsMonitor(@NonNull Context context, - @NonNull Executor executor, @NonNull Delegate delegate) { - super(); - mSubscriptionManager = (SubscriptionManager) context.getSystemService( - Context.TELEPHONY_SUBSCRIPTION_SERVICE); - mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - mExecutor = executor; - mDelegate = delegate; - } - - @Override - public void onSubscriptionsChanged() { - // Collect active subId list, hidden subId such as opportunistic subscriptions are - // also needed to track CBRS. - final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager); - - // IMSI is needed for every newly added sub. Listener stores subscriberId into it to - // prevent binder call to telephony when querying RAT. Keep listener registration with empty - // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported - // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. - final List<Pair<Integer, String>> filteredNewSubs = new ArrayList<>(); - for (final int subId : newSubs) { - final String subscriberId = - mTeleManager.createForSubscriptionId(subId).getSubscriberId(); - if (!TextUtils.isEmpty(subscriberId)) { - filteredNewSubs.add(new Pair(subId, subscriberId)); - } - } - - for (final Pair<Integer, String> sub : filteredNewSubs) { - // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be - // suddenly change regardless of subId, such as switch IMSI feature in modem side. - // If that happens, register new listener with new IMSI and remove old one later. - if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) { - continue; - } - - final RatTypeListener listener = new RatTypeListener(this, sub.first, sub.second); - mRatListeners.add(listener); - - // Register listener to the telephony manager that associated with specific sub. - mTeleManager.createForSubscriptionId(sub.first) - .registerTelephonyCallback(mExecutor, listener); - Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first); - } - - for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { - // If there is no subId and IMSI matched the listener, removes it. - if (!CollectionUtils.any(filteredNewSubs, - it -> listener.equalsKey(it.first, it.second))) { - handleRemoveRatTypeListener(listener); - } - } - } - - @NonNull - private List<Integer> getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { - final ArrayList<Integer> ret = new ArrayList<>(); - final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); - for (int id : ids) ret.add(id); - return ret; - } - - /** - * Get a collapsed RatType for the given subscriberId. - * - * @param subscriberId the target subscriberId - * @return collapsed RatType for the given subscriberId - */ - public int getRatTypeForSubscriberId(@NonNull String subscriberId) { - final int index = CollectionUtils.indexOf(mRatListeners, - it -> TextUtils.equals(subscriberId, it.mSubscriberId)); - return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType - : TelephonyManager.NETWORK_TYPE_UNKNOWN; - } - - /** - * Start monitoring events that triggered per subscription. - */ - public void start() { - mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); - } - - /** - * Unregister subscription changes and all listeners for each subscription. - */ - public void stop() { - mSubscriptionManager.removeOnSubscriptionsChangedListener(this); - - for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { - handleRemoveRatTypeListener(listener); - } - } - - private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { - mTeleManager.createForSubscriptionId(listener.mSubId) - .unregisterTelephonyCallback(listener); - Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); - mRatListeners.remove(listener); - - // Removal of subscriptions doesn't generate RAT changed event, fire it for every - // RatTypeListener. - mDelegate.onCollapsedRatTypeChanged( - listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); - } - - static class RatTypeListener extends TelephonyCallback - implements TelephonyCallback.DisplayInfoListener { - // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. - @NonNull - private final int mSubId; - - // IMSI to identifying the corresponding network from {@link NetworkState}. - // See {@link TelephonyManager#getSubscriberId}. - @NonNull - private final String mSubscriberId; - - private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - @NonNull - private final NetworkStatsSubscriptionsMonitor mMonitor; - - RatTypeListener(@NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, - @NonNull String subscriberId) { - mSubId = subId; - mSubscriberId = subscriberId; - mMonitor = monitor; - } - - @Override - public void onDisplayInfoChanged(TelephonyDisplayInfo displayInfo) { - // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony - // would report RAT = 5G_NR. - // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and - // network allocates a secondary 5G cell so telephony reports RAT = LTE along with - // NR state as connected. In such case, attributes the data usage to NR. - // See b/160727498. - final boolean is5GNsa = displayInfo.getNetworkType() == NETWORK_TYPE_LTE - && (displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_NSA - || displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_ADVANCED); - - final int networkType = - (is5GNsa ? NETWORK_TYPE_5G_NSA : displayInfo.getNetworkType()); - final int collapsedRatType = getCollapsedRatType(networkType); - if (collapsedRatType == mLastCollapsedRatType) return; - - if (NetworkStatsService.LOGD) { - Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " - + mLastCollapsedRatType + " -> " + collapsedRatType); - } - mLastCollapsedRatType = collapsedRatType; - mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); - } - - @VisibleForTesting - public int getSubId() { - return mSubId; - } - - boolean equalsKey(int subId, @NonNull String subscriberId) { - return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId); - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java deleted file mode 100644 index ea8d83638347..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Key for both stats maps. - */ -public class StatsMapKey extends Struct { - @Field(order = 0, type = Type.U32) - public final long uid; - - @Field(order = 1, type = Type.U32) - public final long tag; - - @Field(order = 2, type = Type.U32) - public final long counterSet; - - @Field(order = 3, type = Type.U32) - public final long ifaceIndex; - - public StatsMapKey(final long uid, final long tag, final long counterSet, - final long ifaceIndex) { - this.uid = uid; - this.tag = tag; - this.counterSet = counterSet; - this.ifaceIndex = ifaceIndex; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java deleted file mode 100644 index 48f26ce686e2..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Value used for both stats maps and uid stats map. - */ -public class StatsMapValue extends Struct { - @Field(order = 0, type = Type.U63) - public final long rxPackets; - - @Field(order = 1, type = Type.U63) - public final long rxBytes; - - @Field(order = 2, type = Type.U63) - public final long txPackets; - - @Field(order = 3, type = Type.U63) - public final long txBytes; - - public StatsMapValue(final long rxPackets, final long rxBytes, final long txPackets, - final long txBytes) { - this.rxPackets = rxPackets; - this.rxBytes = rxBytes; - this.txPackets = txPackets; - this.txBytes = txBytes; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java deleted file mode 100644 index 2849f94c9383..000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Key for uid stats map. - */ -public class UidStatsMapKey extends Struct { - @Field(order = 0, type = Type.U32) - public final long uid; - - public UidStatsMapKey(final long uid) { - this.uid = uid; - } -} diff --git a/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java b/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java deleted file mode 100644 index e2253a2151b0..000000000000 --- a/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import static com.android.server.NativeDaemonConnector.appendEscaped; -import static com.android.server.NativeDaemonConnector.makeCommand; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -import com.android.server.NativeDaemonConnector.SensitiveArg; - -/** - * Tests for {@link NativeDaemonConnector}. - */ -@MediumTest -public class NativeDaemonConnectorTest extends AndroidTestCase { - private static final String TAG = "NativeDaemonConnectorTest"; - - public void testArgumentNormal() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, ""); - assertEquals("", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo"); - assertEquals("foo", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\"bar"); - assertEquals("foo\\\"bar", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\\bar\\\"baz"); - assertEquals("foo\\\\bar\\\\\\\"baz", builder.toString()); - } - - public void testArgumentWithSpaces() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, "foo bar"); - assertEquals("\"foo bar\"", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\"bar\\baz foo"); - assertEquals("\"foo\\\"bar\\\\baz foo\"", builder.toString()); - } - - public void testArgumentWithUtf() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, "caf\u00E9 c\u00F6ffee"); - assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString()); - } - - public void testSensitiveArgs() throws Exception { - final StringBuilder rawBuilder = new StringBuilder(); - final StringBuilder logBuilder = new StringBuilder(); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz"); - assertEquals("1 foo bar baz\0", rawBuilder.toString()); - assertEquals("1 foo bar baz", logBuilder.toString()); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz"); - assertEquals("1 foo bar baz\0", rawBuilder.toString()); - assertEquals("1 foo [scrubbed] baz", logBuilder.toString()); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz", - new SensitiveArg("wat")); - assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString()); - assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString()); - } -} diff --git a/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java b/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java deleted file mode 100644 index ad0be5862c5d..000000000000 --- a/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import android.net.InetAddresses; -import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; -import android.net.LinkAddress; -import android.net.ProxyInfo; -import android.net.StaticIpConfiguration; -import android.util.ArrayMap; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Unit tests for {@link IpConfigStore} - */ -@RunWith(AndroidJUnit4.class) -public class IpConfigStoreTest { - private static final int KEY_CONFIG = 17; - private static final String IFACE_1 = "eth0"; - private static final String IFACE_2 = "eth1"; - private static final String IP_ADDR_1 = "192.168.1.10/24"; - private static final String IP_ADDR_2 = "192.168.1.20/24"; - private static final String DNS_IP_ADDR_1 = "1.2.3.4"; - private static final String DNS_IP_ADDR_2 = "5.6.7.8"; - - @Test - public void backwardCompatibility2to3() throws IOException { - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - DataOutputStream outputStream = new DataOutputStream(byteStream); - - final IpConfiguration expectedConfig = - newIpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); - - // Emulate writing to old format. - writeDhcpConfigV2(outputStream, KEY_CONFIG, expectedConfig); - - InputStream in = new ByteArrayInputStream(byteStream.toByteArray()); - ArrayMap<String, IpConfiguration> configurations = IpConfigStore.readIpConfigurations(in); - - assertNotNull(configurations); - assertEquals(1, configurations.size()); - IpConfiguration actualConfig = configurations.get(String.valueOf(KEY_CONFIG)); - assertNotNull(actualConfig); - assertEquals(expectedConfig, actualConfig); - } - - @Test - public void staticIpMultiNetworks() throws Exception { - final ArrayList<InetAddress> dnsServers = new ArrayList<>(); - dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); - dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); - final StaticIpConfiguration staticIpConfiguration1 = new StaticIpConfiguration.Builder() - .setIpAddress(new LinkAddress(IP_ADDR_1)) - .setDnsServers(dnsServers).build(); - final StaticIpConfiguration staticIpConfiguration2 = new StaticIpConfiguration.Builder() - .setIpAddress(new LinkAddress(IP_ADDR_2)) - .setDnsServers(dnsServers).build(); - - ProxyInfo proxyInfo = - ProxyInfo.buildDirectProxy("10.10.10.10", 88, Arrays.asList("host1", "host2")); - - IpConfiguration expectedConfig1 = newIpConfiguration(IpAssignment.STATIC, - ProxySettings.STATIC, staticIpConfiguration1, proxyInfo); - IpConfiguration expectedConfig2 = newIpConfiguration(IpAssignment.STATIC, - ProxySettings.STATIC, staticIpConfiguration2, proxyInfo); - - ArrayMap<String, IpConfiguration> expectedNetworks = new ArrayMap<>(); - expectedNetworks.put(IFACE_1, expectedConfig1); - expectedNetworks.put(IFACE_2, expectedConfig2); - - MockedDelayedDiskWrite writer = new MockedDelayedDiskWrite(); - IpConfigStore store = new IpConfigStore(writer); - store.writeIpConfigurations("file/path/not/used/", expectedNetworks); - - InputStream in = new ByteArrayInputStream(writer.byteStream.toByteArray()); - ArrayMap<String, IpConfiguration> actualNetworks = IpConfigStore.readIpConfigurations(in); - assertNotNull(actualNetworks); - assertEquals(2, actualNetworks.size()); - assertEquals(expectedNetworks.get(IFACE_1), actualNetworks.get(IFACE_1)); - assertEquals(expectedNetworks.get(IFACE_2), actualNetworks.get(IFACE_2)); - } - - private IpConfiguration newIpConfiguration(IpAssignment ipAssignment, - ProxySettings proxySettings, StaticIpConfiguration staticIpConfig, ProxyInfo info) { - final IpConfiguration config = new IpConfiguration(); - config.setIpAssignment(ipAssignment); - config.setProxySettings(proxySettings); - config.setStaticIpConfiguration(staticIpConfig); - config.setHttpProxy(info); - return config; - } - - // This is simplified snapshot of code that was used to store values in V2 format (key as int). - private static void writeDhcpConfigV2(DataOutputStream out, int configKey, - IpConfiguration config) throws IOException { - out.writeInt(2); // VERSION 2 - switch (config.getIpAssignment()) { - case DHCP: - out.writeUTF("ipAssignment"); - out.writeUTF(config.getIpAssignment().toString()); - break; - default: - fail("Not supported in test environment"); - } - - out.writeUTF("id"); - out.writeInt(configKey); - out.writeUTF("eos"); - } - - /** Synchronously writes into given byte steam */ - private static class MockedDelayedDiskWrite extends DelayedDiskWrite { - final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream(); - - @Override - public void write(String filePath, Writer w) { - DataOutputStream outputStream = new DataOutputStream(mByteStream); - - try { - w.onWriteCalled(outputStream); - } catch (IOException e) { - fail(); - } - } - } -} diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index 1b7298a332de..9a80b0267976 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -51,6 +51,7 @@ android_library { "SettingsLibSettingsTransition", "SettingsLibButtonPreference", "setupdesign", + "zxing-core-1.7", ], // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java new file mode 100644 index 000000000000..bc5824a4758d --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.qrcode; + +import android.graphics.Bitmap; +import android.graphics.Color; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; + +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public final class QrCodeGenerator { + /** + * Generates a barcode image with {@code contents}. + * + * @param contents The contents to encode in the barcode + * @param size The preferred image size in pixels + * @return Barcode bitmap + */ + public static Bitmap encodeQrCode(String contents, int size) + throws WriterException, IllegalArgumentException { + final Map<EncodeHintType, Object> hints = new HashMap<>(); + if (!isIso88591(contents)) { + hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name()); + } + + final BitMatrix qrBits = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, + size, size, hints); + final Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565); + for (int x = 0; x < size; x++) { + for (int y = 0; y < size; y++) { + bitmap.setPixel(x, y, qrBits.get(x, y) ? Color.BLACK : Color.WHITE); + } + } + return bitmap; + } + + private static boolean isIso88591(String contents) { + CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder(); + return encoder.canEncode(contents); + } +} diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 955aee940513..03384a231e2e 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -110,7 +110,7 @@ <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" /> <uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" /> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> - <uses-permission android:name="android.permission.SEND_LOST_MODE_LOCATION_UPDATES" /> + <uses-permission android:name="android.permission.TRIGGER_LOST_MODE" /> <!-- ACCESS_BACKGROUND_LOCATION is needed for testing purposes only. --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <!-- ACCESS_MTP is needed for testing purposes only. --> diff --git a/packages/SystemUI/docs/broadcasts.md b/packages/SystemUI/docs/broadcasts.md index e75ae29f407d..0a357251ea36 100644 --- a/packages/SystemUI/docs/broadcasts.md +++ b/packages/SystemUI/docs/broadcasts.md @@ -21,6 +21,7 @@ The dispatcher supports `BroadcastReceiver` dynamic subscriptions in the followi * The `IntentFilter` may or may not contain categories. * The `IntentFilter` **does not** contain data types, data schemes, data authorities or data paths. * The broadcast **is not** gated behind a permission. +* The broadcast **is not** ordered and doesn't need to set result data. Additionally, the dispatcher supports the following: @@ -107,3 +108,8 @@ fun unregisterReceiverForUser(BroadcastReceiver, UserHandle) ``` Unregistering can be done even if the `BroadcastReceiver` has never been registered with `BroadcastDispatcher`. In that case, it is a No-Op. + +### A note on goAsync() + +If you're processing a broadcast in a background thread, you shouldn't call `goAsync()` and +`finish()`. The system will keep sysui alive regardless, so it isn't needed. diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java index 8ad200951eb4..75d95e6d85e3 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java @@ -123,6 +123,11 @@ public interface QS extends FragmentBase { default void setScrollListener(ScrollListener scrollListener) {} /** + * Sets the amount of vertical over scroll that should be performed on QS. + */ + default void setOverScrollAmount(int overScrollAmount) {} + + /** * Callback for when QSPanel container is scrolled */ @ProvidesInterface(version = ScrollListener.VERSION) diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml index 166be1bf9fef..8e58b901223c 100644 --- a/packages/SystemUI/res-keyguard/values-sv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml @@ -21,7 +21,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Ange pinkoden"</string> - <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ange det grafiska lösenordet"</string> + <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Ange mönstret"</string> <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Ange ditt lösenord"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ogiltigt kort."</string> <string name="keyguard_charged" msgid="5478247181205188995">"Laddat"</string> diff --git a/packages/SystemUI/res/drawable/ic_media_pause.xml b/packages/SystemUI/res/drawable/ic_media_pause.xml index 1f4b2cf6455e..0009b6cf9949 100644 --- a/packages/SystemUI/res/drawable/ic_media_pause.xml +++ b/packages/SystemUI/res/drawable/ic_media_pause.xml @@ -1,26 +1,91 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="14dp" - android:height="16dp" - android:viewportWidth="14" - android:viewportHeight="16"> - <path - android:pathData="M9.1818,15.6363H13.5455V0.3635H9.1818V15.6363ZM0.4546,15.6363H4.8182V0.3635H0.4546V15.6363Z" - android:fillColor="#FFFFFF" - android:fillType="evenOdd"/> -</vector>
\ No newline at end of file +<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G"
+ android:translateX="12"
+ android:translateY="12.125">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "/>
+ </group>
+ <group android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12.125">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
+ android:valueTo="M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "
+ android:valueTo="M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="517"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_media_pause_container.xml b/packages/SystemUI/res/drawable/ic_media_pause_container.xml new file mode 100644 index 000000000000..b92e63575b95 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_media_pause_container.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G"
+ android:translateX="24"
+ android:translateY="24"
+ android:scaleX="0.5"
+ android:scaleY="0.5"/>
+ <group android:name="_R_G_L_0_G"
+ android:translateX="24"
+ android:translateY="24"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffddb3"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="500"
+ android:startOffset="0"
+ android:valueFrom="M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "
+ android:valueTo="M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.526,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="517"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_media_play.xml b/packages/SystemUI/res/drawable/ic_media_play.xml index 0eac1ad12c1d..eb32470050a5 100644 --- a/packages/SystemUI/res/drawable/ic_media_play.xml +++ b/packages/SystemUI/res/drawable/ic_media_play.xml @@ -1,26 +1,91 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M20,12L6,21V3L20,12ZM15.26,12L8.55,7.68V16.32L15.26,12Z" - android:fillColor="#FFFFFF" - android:fillType="evenOdd"/> -</vector>
\ No newline at end of file +<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24"
+ android:viewportWidth="24">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_1_G"
+ android:translateX="12"
+ android:translateY="12.125">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "/>
+ </group>
+ <group android:name="_R_G_L_0_G"
+ android:translateX="12"
+ android:translateY="12.125">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffffff"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_1_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M-6 7 C-6,7 -2,3.94 -2,3.94 C-2,3.94 -2,-4.37 -2,-4.37 C-2,-4.37 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
+ android:valueTo="M-6 7 C-6,7 -2,7 -2,7 C-2,7 -2,-7 -2,-7 C-2,-7 -6,-7 -6,-7 C-6,-7 -6,7 -6,7c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="333"
+ android:startOffset="0"
+ android:valueFrom="M-5.62 7 C-5.62,7 -4.75,7 -4.75,7 C-4.75,7 6,-0.12 6,-0.12 C6,-0.12 -4.44,-7 -4.44,-7 C-4.44,-7 -5.62,-7 -5.62,-7 C-5.62,-7 -5.62,7 -5.62,7c "
+ android:valueTo="M2 7 C2,7 6,7 6,7 C6,7 6,-0.12 6,-0.12 C6,-0.12 6,-7 6,-7 C6,-7 2,-7 2,-7 C2,-7 2,7 2,7c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="517"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_media_play_container.xml b/packages/SystemUI/res/drawable/ic_media_play_container.xml new file mode 100644 index 000000000000..2fc9fc88a4fd --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_media_play_container.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48">
+ <group android:name="_R_G">
+ <group android:name="_R_G_L_0_G"
+ android:translateX="24"
+ android:translateY="24"
+ android:scaleX="0.5"
+ android:scaleY="0.5">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillColor="#ffddb3"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "/>
+ </group>
+ </group>
+ <group android:name="time_group"/>
+ </vector>
+ </aapt:attr>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="pathData"
+ android:duration="500"
+ android:startOffset="0"
+ android:valueFrom="M48 0.25 C48,0.25 48,0 48,0 C47.75,26 31.25,48 0,48 C0,48 0,48 0,48 C-30,48 -48,25.75 -48,-0.25 C-48,-0.25 -48,-0.25 -48,-0.25 C-47.75,-23.5 -32.25,-47.75 0.5,-48 C0.5,-48 0.5,-48 0.5,-48 C28,-47.75 47.75,-29.75 48,0.25c "
+ android:valueTo="M48 -16 C48,-16 48,16 48,16 C48,33.67 33.67,48 16,48 C16,48 -16,48 -16,48 C-33.67,48 -48,33.67 -48,16 C-48,16 -48,-16 -48,-16 C-48,-33.67 -33.67,-48 -16,-48 C-16,-48 16,-48 16,-48 C33.67,-48 48,-33.67 48,-16c "
+ android:valueType="pathType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.518,0 0,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="translateX"
+ android:duration="517"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"/>
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml index 111735623bc2..e1f3eca3fd63 100644 --- a/packages/SystemUI/res/layout/media_session_view.xml +++ b/packages/SystemUI/res/layout/media_session_view.xml @@ -145,8 +145,7 @@ android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="@dimen/qs_media_padding" - android:layout_marginEnd="@dimen/qs_media_padding" - /> + android:layout_marginEnd="@dimen/qs_media_padding" /> <!-- See comment in media_session_collapsed.xml for how these barriers are used --> <androidx.constraintlayout.widget.Barrier @@ -184,7 +183,7 @@ <!-- Button visibility will be controlled in code --> <ImageButton android:id="@+id/actionPrev" - style="@style/MediaPlayer.SessionAction" + style="@style/MediaPlayer.SessionAction.Secondary" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="4dp" @@ -211,7 +210,7 @@ <ImageButton android:id="@+id/actionNext" - style="@style/MediaPlayer.SessionAction" + style="@style/MediaPlayer.SessionAction.Secondary" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="0dp" @@ -221,7 +220,7 @@ <ImageButton android:id="@+id/action0" - style="@style/MediaPlayer.SessionAction" + style="@style/MediaPlayer.SessionAction.Secondary" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="@dimen/qs_media_action_spacing" @@ -231,7 +230,7 @@ <ImageButton android:id="@+id/action1" - style="@style/MediaPlayer.SessionAction" + style="@style/MediaPlayer.SessionAction.Secondary" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="@dimen/qs_media_action_spacing" @@ -241,7 +240,7 @@ <ImageButton android:id="@+id/action2" - style="@style/MediaPlayer.SessionAction" + style="@style/MediaPlayer.SessionAction.Secondary" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="@dimen/qs_media_action_spacing" @@ -251,7 +250,7 @@ <ImageButton android:id="@+id/action3" - style="@style/MediaPlayer.SessionAction" + style="@style/MediaPlayer.SessionAction.Secondary" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="@dimen/qs_media_action_spacing" @@ -261,7 +260,7 @@ <ImageButton android:id="@+id/action4" - style="@style/MediaPlayer.SessionAction" + style="@style/MediaPlayer.SessionAction.Secondary" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginStart="@dimen/qs_media_action_spacing" diff --git a/packages/SystemUI/res/layout/rounded_corners_bottom.xml b/packages/SystemUI/res/layout/rounded_corners_bottom.xml new file mode 100644 index 000000000000..bb6d4bddf25a --- /dev/null +++ b/packages/SystemUI/res/layout/rounded_corners_bottom.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** 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. +--> +<com.android.systemui.RegionInterceptingFrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/rounded_corners_bottom" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <ImageView + android:id="@+id/left" + android:layout_width="12dp" + android:layout_height="12dp" + android:layout_gravity="left|bottom" + android:tint="#ff000000" + android:visibility="gone" + android:src="@drawable/rounded_corner_bottom"/> + + <ImageView + android:id="@+id/right" + android:layout_width="12dp" + android:layout_height="12dp" + android:tint="#ff000000" + android:visibility="gone" + android:layout_gravity="right|bottom" + android:src="@drawable/rounded_corner_bottom"/> + +</com.android.systemui.RegionInterceptingFrameLayout> diff --git a/packages/SystemUI/res/layout/rounded_corners_top.xml b/packages/SystemUI/res/layout/rounded_corners_top.xml new file mode 100644 index 000000000000..46648c88d921 --- /dev/null +++ b/packages/SystemUI/res/layout/rounded_corners_top.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** 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. +--> +<com.android.systemui.RegionInterceptingFrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/rounded_corners_top" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <ImageView + android:id="@+id/left" + android:layout_width="12dp" + android:layout_height="12dp" + android:layout_gravity="left|top" + android:tint="#ff000000" + android:visibility="gone" + android:src="@drawable/rounded_corner_top"/> + + <ImageView + android:id="@+id/right" + android:layout_width="12dp" + android:layout_height="12dp" + android:tint="#ff000000" + android:visibility="gone" + android:layout_gravity="right|top" + android:src="@drawable/rounded_corner_top"/> + +</com.android.systemui.RegionInterceptingFrameLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 8d09d7621042..32eb3ad1c725 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"As jy met jou volgende poging \'n verkeerde patroon invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"As jy met jou volgende poging \'n verkeerde PIN invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"As jy met jou volgende poging \'n verkeerde wagwoord invoer, sal jou werkprofiel en die data daarvan uitgevee word."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Te veel verkeerde pogings. Hierdie toestel se data sal uitgevee word."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Te veel verkeerde pogings. Hierdie gebruiker sal uitgevee word."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Te veel verkeerde pogings. Hierdie werkprofiel en sy data sal uitgevee word."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Maak toe"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak die vingerafdruksensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Vingerafdrukikoon"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans stadig • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laaidok • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string> - <string name="user_add_user" msgid="4336657383006913022">"Voeg gebruiker by"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nuwe gebruiker"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Verwyder gas?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwyder"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gas!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wiil jy jou sessie voortsit?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Begin van voor af"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, gaan voort"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Voeg nuwe gebruiker by?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel.\n\nEnige gebruiker kan programme vir al die ander gebruikers opdateer."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Gebruikerlimiet is bereik"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Jy kan tot <xliff:g id="COUNT">%d</xliff:g> gebruikers byvoeg.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontsluit om te gebruik"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Kon nie jou kaarte kry nie; probeer later weer"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Sluitskerminstellings"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skandeer QR-kode"</string> <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Jy sal nie jou volgende wekker <xliff:g id="WHEN">%1$s</xliff:g> hoor nie"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swiep om meer te sien"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laai tans aanbevelings"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Versteek hierdie mediasessie?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Die huidige mediasessie kan nie versteek word nie."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Maak toe"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Versteek"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> deur <xliff:g id="ARTIST_NAME">%2$s</xliff:g> speel tans vanaf <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Beweeg nader aan <xliff:g id="DEVICENAME">%1$s</xliff:g> om hier te speel"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Speel tans op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Speel tans op hierdie foon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Iets is fout"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 83c018494a92..28f35d38875a 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ ሥርዓተ ጥለት ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ ፒን ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ የይለፍ ቃል ካስገቡ የእርስዎ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"በጣም ብዙ ትክክል ያልሆኑ ሙከራዎች። ይህ የመሣሪያ ውሂብ ይሰረዛል።"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"በጣም ብዙ ትክክል ያልሆኑ ሙከራዎች። ይህ ተጠቃሚ ይሰረዛል።"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"በጣም ብዙ ትክክል ያልሆኑ ሙከራዎች። የዚህ የሥራ መገለጫ እና ውሂቡ ይሰረዛሉ።"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"አሰናብት"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"የጣት አሻራ ዳሳሹን ይንኩ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"የጣት አሻራ አዶ"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • የባትሪ ኃይል መሙያ መትከያ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string> - <string name="user_add_user" msgid="4336657383006913022">"ተጠቃሚ አክል"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"አዲስ ተጠቃሚ"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"እንግዳ ይወገድ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"አስወግድ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"አዎ፣ ቀጥል"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"አዲስ ተጠቃሚ ይታከል?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"እርስዎ አንድ አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሱ ቦታ ማዘጋጀት አለበት።\n\nማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ሊያዘምን ይችላል።"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"የተጠቃሚ ገደብ ላይ ተደርሷል"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> ተጠቃሚዎች ብቻ ናቸው ሊፈጠሩ የሚችሉት።</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ለማየት ይክፈቱ"</string> <string name="wallet_error_generic" msgid="257704570182963611">"የእርስዎን ካርዶች ማግኘት ላይ ችግር ነበር፣ እባክዎ ቆይተው እንደገና ይሞክሩ"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"የገጽ መቆለፊያ ቅንብሮች"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ኮድ ቃኝ"</string> <string name="status_bar_work" msgid="5238641949837091056">"የስራ መገለጫ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"የአውሮፕላን ሁነታ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"የእርስዎን ቀጣይ ማንቂያ <xliff:g id="WHEN">%1$s</xliff:g> አይሰሙም"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ተጨማሪ ለማየት ያንሸራትቱ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ምክሮችን በመጫን ላይ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ሚዲያ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ይህ የሚዲያ ክፍለ ጊዜ ይደበቅ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"የአሁኑ የሚዲያ ክፍለ ጊዜ ሊደበቅ አይቻልም።"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"አሰናብት"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ደብቅ"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> በ<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ከ<xliff:g id="APP_LABEL">%3$s</xliff:g> እየተጫወተ ነው"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"እዚህ ለመጫወት ወደ <xliff:g id="DEVICENAME">%1$s</xliff:g> ቀረብ ይበሉ"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"በ<xliff:g id="DEVICENAME">%1$s</xliff:g> ላይ በማጫወት ላይ"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"በዚህ ስልክ በመጫወት ላይ"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"የሆነ ችግር ተፈጥሯል"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 24e36fb5866f..e41e0493f982 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"عند إدخال نقش غير صحيح في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"عند إدخال رقم تعريف شخصي غير صحيح في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"عند إدخال كلمة مرور غير صحيحة في المحاولة التالية، سيتم حذف ملفك الشخصي للعمل وبياناته."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف بيانات هذا الجهاز."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف هذا المستخدم."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف الملف الشخصي للعمل وبياناته."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"إغلاق"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"المس مستشعر بصمة الإصبع"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"رمز بصمة الإصبع"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string> @@ -331,17 +327,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن ببطء • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن على وحدة الإرساء • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string> - <string name="user_add_user" msgid="4336657383006913022">"إضافة مستخدم"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"مستخدم جديد"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"هل تريد إزالة جلسة الضيف؟"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"إزالة"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"نعم، متابعة"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"هل تريد إضافة مستخدم جديد؟"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"عند إضافة مستخدم جديد، عليه إعداد مساحته.\n\nويُمكن لأي مستخدم تحديث التطبيقات لجميع المستخدمين الآخرين."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"تم الوصول إلى أقصى عدد للمستخدمين"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="zero">يمكنك إضافة ما يصل إلى <xliff:g id="COUNT">%d</xliff:g> مستخدم.</item> @@ -809,9 +800,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"مرّر سريعًا لرؤية المزيد."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"جارٍ تحميل الاقتراحات"</string> <string name="controls_media_title" msgid="1746947284862928133">"الوسائط"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"هل تريد إخفاء جلسة الوسائط هذه؟"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"لا يمكن إخفاء جلسة الوسائط الحالية."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"إغلاق"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"إخفاء"</string> <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"الإعدادات"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"يتم تشغيل <xliff:g id="SONG_NAME">%1$s</xliff:g> للفنان <xliff:g id="ARTIST_NAME">%2$s</xliff:g> من تطبيق <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> @@ -829,7 +821,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"يُرجى الاقتراب من <xliff:g id="DEVICENAME">%1$s</xliff:g> لتشغيل الوسائط هنا."</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"جارٍ تشغيل الوسائط على <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"جارٍ تشغيل الوسائط على هذا الهاتف"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"حدث خطأ."</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string> <string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string> @@ -926,7 +919,7 @@ <item quantity="one">تطبيق واحد (<xliff:g id="COUNT_0">%s</xliff:g>) نشط</item> </plurals> <string name="fgs_dot_content_description" msgid="2865071539464777240">"معلومات جديدة"</string> - <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"# تطبيق نشط"</string> + <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"التطبيقات النشطة"</string> <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"إيقاف"</string> <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقّف"</string> <string name="clipboard_edit_text_copy" msgid="770856373439969178">"نسخ"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 7bb97a78d214..81013223fa9b 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল আৰ্হি দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল পিন দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল পাছৱৰ্ড দিলে, আপোনাৰ কৰ্মস্থানৰ প্ৰ’ফাইল আৰু ইয়াৰ ডেটা মচি পেলোৱা হ’ব।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"বহুসংখ্যক ভুল প্ৰয়াস। এই ডিভাইচটোৰ ডেটা মচা হ\'ব।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"বহুসংখ্যক ভুল প্ৰয়াস। এই ব্যৱহাৰকাৰীক মচা হ\'ব।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"বহুসংখ্যক ভুল প্ৰয়াস। এই কৰ্মস্থানৰ প্ৰ\'ফাইলটো আৰু তাৰ লগত জড়িত ডেটা মচা হ\'ব।"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"অগ্ৰাহ্য কৰক"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ফিংগাৰপ্ৰিণ্ট আইকন"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • লাহে লাহে চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জিং ডক • সম্পূৰ্ণ হ’বলৈ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগিব"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string> - <string name="user_add_user" msgid="4336657383006913022">"ব্যৱহাৰকাৰী যোগ কৰক"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যৱহাৰকাৰী"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি আঁতৰাবনে?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"আঁতৰাওক"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপোনাক পুনৰ স্বাগতম!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আকৌ আৰম্ভ কৰক"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"হয়, অব্যাহত ৰাখক"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"নতুন ব্যৱহাৰকাৰী যোগ কৰিবনে?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰী যোগ কৰে, তেওঁ নিজৰ স্থান ছেট আপ কৰা প্ৰয়োজন।\n\nযিকোনো ব্যৱহাৰকাৰীয়ে নিজৰ লগতে আন ব্যৱহাৰকাৰীৰো এপ্ আপডে’ট কৰিব পাৰে।"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"অধিকতম ব্যৱহাৰকাৰী সৃষ্টি কৰা হ’ল"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">আপুনি <xliff:g id="COUNT">%d</xliff:g> জনলৈকে ব্যৱহাৰকাৰী যোগ কৰিব পাৰে।</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যৱহাৰ কৰিবলৈ আনলক কৰক"</string> <string name="wallet_error_generic" msgid="257704570182963611">"আপোনাৰ কাৰ্ড লাভ কৰোঁতে এটা সমস্যা হৈছে, অনুগ্ৰহ কৰি পাছত পুনৰ চেষ্টা কৰক"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্ৰীনৰ ছেটিং"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"কিউআৰ ক’ড স্কেন কৰক"</string> <string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লেইন ম\'ড"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"অধিক চাবলৈ ছোৱাইপ কৰক"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string> <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"এই মিডিয়াৰ ছেশ্বনটো লুকুৱাবনে?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"বৰ্তমানৰ মিডিয়াৰ ছেশ্বনটো লুকুৱাব নোৱাৰি।"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"অগ্ৰাহ্য কৰক"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকুৱাওক"</string> <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিং"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ত <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ৰ <xliff:g id="SONG_NAME">%1$s</xliff:g> গীতটো প্লে’ হৈ আছে"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ইয়াত খেলিবলৈ <xliff:g id="DEVICENAME">%1$s</xliff:g>ৰ আৰু ওচৰলৈ যাওক"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ত প্লে কৰি থকা হৈছে"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"এই ফ’নটোত প্লে কৰি থকা হৈছে"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"কিবা ভুল হ’ল"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string> <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index a796a201834a..c9388b5c55dd 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Növbəti cəhddə yanlış model daxil etsəniz, iş profili və datası silinəcək."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Növbəti cəhddə yanlış PIN daxil etsəniz, iş profili və datası silinəcək."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Növbəti cəhddə yanlış parol daxil etsəniz, iş profili və datası silinəcək."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Həddindən artıq yanlış cəhd. Bu cihazın datası silinəcək."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Həddindən artıq yanlış cəhd. Bu istifadəçi silinəcək."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Həddindən artıq yanlış cəhd. Bu iş profili və oradakı data silinəcək."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ötürün"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmaq izi sensoruna klikləyin"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Barmaq izi ikonası"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Asta şarj edilir • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj Doku • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> - <string name="user_add_user" msgid="4336657383006913022">"İstifadəçi əlavə edin"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Yeni istifadəçi"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Qonaq silinsin?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Yığışdır"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xoş gəlmisiniz!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Sessiya davam etsin?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Yenidən başlayın"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Bəli, davam edin"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Yeni istifadəçi əlavə edilsin?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Yeni istifadəçi əlavə etdiyiniz zaman həmin şəxs öz yerini quraşdırmalıdır. \n\n İstənilən istifadəçi bütün digər istifadəçilərdən olan tətbiqləri güncəlləşdirə bilər."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"İstifadəçi limitinə çatmısınız"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Maksimum <xliff:g id="COUNT">%d</xliff:g> istifadəçi əlavə edə bilərsiniz.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Digərlərini görmək üçün sürüşdürün"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tövsiyələr yüklənir"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Bu media sessiyası gizlədilsin?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Cari media sessiyası gizlədilə bilməz."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"İmtina edin"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizlədin"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> tərəfindən <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> tətbiqindən oxudulur"</string> @@ -804,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oxutmaq üçün <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaxınlaşın"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oxudulur"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda oxudulur"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Xəta oldu"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index cd6b9cc147b5..2e0e503184f4 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako unesete netačan šablon pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako unesete netačan PIN pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako unesete netačnu lozinku pri sledećem pokušaju, izbrisaćemo poslovni profil i njegove podatke."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Previše netačnih pokušaja. Izbrisaćemo podatke sa ovog uređaja."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Previše netačnih pokušaja. Izbrisaćemo ovog korisnika."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše netačnih pokušaja. Izbrisaćemo ovaj poslovni profil i njegove podatke."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Odbaci"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otiska prsta"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string> @@ -325,17 +321,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo se puni • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bazna stanica za punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string> - <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite li da uklonite gosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Dodajete novog korisnika?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor.\n\nSvaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Dostignut maksimalni broj korisnika"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Možete da dodate najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item> @@ -790,9 +781,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da biste videli još"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavaju se preporuke"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Želite li da sakrijete ovu sesiju medija?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Aktuelna sesija medija ne može da bude sakrivena."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se pušta iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -810,7 +802,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu puštali"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Pušta se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Pušta se na ovom telefonu"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Došlo je do greške"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 0380a764e179..ea9d9cacd72e 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Калі вы ўведзяце няправільны ўзор разблакіроўкі яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Калі вы ўведзяце няправільны PIN-код яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Калі вы ўведзяце няправільны пароль яшчэ раз, ваш працоўны профіль і звязаныя з ім даныя будуць выдалены."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Занадта шмат няўдалых спроб. Даныя будуць выдалены з гэтай прылады."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Занадта шмат няўдалых спроб. Гэты карыстальнік будзе выдалены."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Занадта шмат няўдалых спроб. Гэты працоўны профіль і звязаныя з ім даныя будуць выдалены."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Адхіліць"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Дакраніцеся да сканера адбіткаў пальцаў"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок адбіткаў пальцаў"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе павольная зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка праз док-станцыю • Поўнасцю зарадзіцца праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string> - <string name="user_add_user" msgid="4336657383006913022">"Дадаць карыстальніка"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Новы карыстальнік"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Выдаліць госця?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Выдаліць"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Так, працягнуць"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Дадаць новага карыстальніка?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Пасля стварэння профілю яго трэба наладзіць.\n\nЛюбы карыстальнік прылады можа абнаўляць праграмы ўсіх іншых карыстальнікаў."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Дасягнуты ліміт карыстальнікаў"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Можна дадаць <xliff:g id="COUNT">%d</xliff:g> карыстальніка.</item> @@ -465,8 +456,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Разблакіраваць для выкарыстання"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Узнікла праблема з загрузкай вашых карт. Паўтарыце спробу пазней"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Налады экрана блакіроўкі"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Сканіраванне QR-кода"</string> <string name="status_bar_work" msgid="5238641949837091056">"Працоўны профіль"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Рэжым палёту"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -797,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Правядзіце пальцам, каб убачыць больш інфармацыі"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загружаюцца рэкамендацыі"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мультымедыя"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Схаваць гэты сеанс мультымедыя?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Не ўдалося схаваць бягучы сеанс мультымедыя."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Адхіліць"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Схаваць"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налады"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"У праграме \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\" прайграецца кампазіцыя \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", выканаўца – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string> @@ -817,7 +808,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Падыдзіце бліжэй да прылады \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\", каб прайграць на гэтай"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Прайграецца на прыладзе \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\""</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Прайграецца на гэтым тэлефоне"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Нешта пайшло не так"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index f56e57d4a6cf..25c90ce714f7 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако въведете неправилна фигура при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако въведете неправилен ПИН код при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако въведете неправилна парола при следващия опит, служебният ви потребителски профил и данните в него ще бъдат изтрити."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Твърде много неправилни опити. Данните от това устройство ще бъдат изтрити."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Твърде много неправилни опити. Този потребител ще бъде изтрит."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Твърде много неправилни опити. Този служебен потребителски профил и данните в него ще бъдат изтрити."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Отхвърляне"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Докоснете сензора за отпечатъци"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона за отпечатък"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарежда се бавно • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Докинг станция за зареждане • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string> - <string name="user_add_user" msgid="4336657383006913022">"Добавяне на потребител"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Нов потребител"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се премахне ли гостът?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Премахване"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дошли отново в сесията като гост!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Искате ли да продължите сесията си?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Започване отначало"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продължавам"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Да се добави ли нов потребител?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Когато добавите нов потребител, той трябва да настрои работното си пространство.\n\nВсеки потребител може да актуализира приложенията за всички останали потребители."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнахте огранич. за потребители"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Можете да добавите до <xliff:g id="COUNT">%d</xliff:g> потребители.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отключване с цел използване"</string> <string name="wallet_error_generic" msgid="257704570182963611">"При извличането на картите ви възникна проблем. Моля, опитайте отново по-късно"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Настройки за заключения екран"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Сканиране на QR код"</string> <string name="status_bar_work" msgid="5238641949837091056">"Потребителски профил в Work"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Самолетен режим"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Няма да чуете следващия си будилник в <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Прекарайте пръст, за да видите повече"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мултимедия"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Да се скрие ли тази сесия за мултимедия?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Текущата сесия за мултимедия не бе скрита."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Отхвърляне"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скриване"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> на <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се възпроизвежда от <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за възпроизвеждане на това устройство"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Възпроизвежда се на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Възпроизвежда се на този телефон"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Нещо се обърка"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 2730b4cc3ebf..a967a5c3399b 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"আপনি পরের বারও ভুল প্যাটার্ন দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"আপনি পরের বারও ভুল পিন দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"আপনি পরের বারও ভুল পাসওয়ার্ড দিলে আপনার অফিস প্রোফাইল এবং তার ডেটা মুছে দেওয়া হবে।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"বহুবার ভুল লেখা হয়েছে। এই ডিভাইসের ডেটা মুছে যাবে।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"বহুবার ভুল লেখা হয়েছে। এই ব্যবহারকারীর ডেটা মুছে যাবে।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"বহুবার ভুল লেখা হয়েছে। এই অফিসের প্রোফাইল ও সংশ্লিষ্ট ডেটা মুছে যাবে।"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"বাতিল করুন"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"আঙ্গুলের ছাপের সেন্সর স্পর্শ করুন"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"আঙ্গুলের ছাপের আইকন"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ধীরে চার্জ হচ্ছে • পুরো চার্জ হতে <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগবে"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চার্জিং ডক • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-এর মধ্যে সম্পূর্ণ হয়ে যাবে"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string> - <string name="user_add_user" msgid="4336657383006913022">"ব্যবহারকারী জুড়ুন"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যবহারকারী"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি সরাবেন?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"সরান"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি চালিয়ে যেতে চান?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"হ্যাঁ, চালিয়ে যান"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"নতুন ব্যবহারকারীকে যোগ করবেন?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"আপনি একজন নতুন ব্যবহারকারী যোগ করলে তাকে তার জায়গা সেট-আপ করে নিতে হবে৷\n\nযেকোনও ব্যবহারকারী অন্য সব ব্যবহারকারীর জন্য অ্যাপ আপডেট করতে পারবেন৷"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"আর কোনও প্রোফাইল যোগ করা যাবে না"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">আপনি <xliff:g id="COUNT">%d</xliff:g> জন পর্যন্ত ব্যবহারকারীর প্রোফাইল যোগ করতে পারেন।</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ব্যবহার করতে আনলক করুন"</string> <string name="wallet_error_generic" msgid="257704570182963611">"আপনার কার্ড সংক্রান্ত তথ্য পেতে সমস্যা হয়েছে, পরে আবার চেষ্টা করুন"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"লক স্ক্রিন সেটিংস"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR কোড স্ক্যান করুন"</string> <string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"আরও দেখতে সোয়াইপ করুন"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string> <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"এই মিডিয়া সেশন লুকিয়ে রাখতে চান?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"বর্তমান মিডিয়া সেশন লুকিয়ে রাখা যাবে না।"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"খারিজ করুন"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকান"</string> <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>-এর <xliff:g id="SONG_NAME">%1$s</xliff:g> গানটি <xliff:g id="APP_LABEL">%3$s</xliff:g> অ্যাপে চলছে"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"এখান থেকে চালাতে <xliff:g id="DEVICENAME">%1$s</xliff:g>-এর কাছে নিয়ে যান"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>-এ ভিডিও চালানো হচ্ছে"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"এই ফোনে চালানো হচ্ছে"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"কোনও সমস্যা হয়েছে"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"কোনও সমস্যা হয়েছে। আবার চেষ্টা করুন।"</string> <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string> <string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 00973eee5674..c5a73e5f8239 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako u sljedećem pokušaju unesete neispravan uzorak, vaš radni profil i njegovi podaci će se izbrisati."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako u sljedećem pokušaju unesete neispravan PIN, vaš radni profil i njegovi podaci će se izbrisati."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako u sljedećem pokušaju unesete neispravnu lozinku, vaš radni profil i njegovi podaci će se izbrisati."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Previše je neispravnih pokušaja. Podaci ovog uređaja će se izbrisati."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Previše je neispravnih pokušaja. Ovaj korisnik će se izbrisati."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše je neispravnih pokušaja. Ovaj radni profil i njegovi podaci će se izbrisati."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Odbaci"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona za otisak prsta"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string> @@ -325,17 +321,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Priključna stanica za punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string> - <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Dodati novog korisnika?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor.\n\nSvaki korisnik može ažurirati aplikacije za sve ostale korisnike."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Dostignut limit za broj korisnika"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item> @@ -462,7 +453,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Otključajte da koristite"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Došlo je do problema prilikom preuzimanja vaših kartica. Pokušajte ponovo kasnije"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Postavke zaključavanja ekrana"</string> - <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skeniraj QR kôd"</string> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skenirajte QR kôd"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil za posao"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -790,9 +781,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da vidite više"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Sakriti ovu sesiju medija?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Trenutna sesija medija se ne može sakriti."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Pjesma <xliff:g id="SONG_NAME">%1$s</xliff:g> izvođača <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se reproducira pomoću aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -810,7 +802,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da na njemu reproducirate"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducira se na ovom telefonu"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Nešto nije uredu"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 975f4e0f1f53..13abf7543ae0 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si tornes a introduir un patró incorrecte, se suprimirà el perfil de treball i les dades que contingui."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si tornes a introduir un PIN incorrecte, se suprimirà el perfil de treball i les dades que contingui."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si tornes a introduir una contrasenya incorrecta, se suprimirà el perfil de treball i les dades que contingui."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Has superat el nombre d\'intents incorrectes permesos. Se suprimiran les dades del dispositiu."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Has superat el nombre d\'intents incorrectes permesos. Se suprimirà l\'usuari."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Has superat el nombre d\'intents incorrectes permesos. Se suprimirà el perfil de treball i les dades que contingui."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignora"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor d\'empremtes digitals"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona d\'empremta digital"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant lentament • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de càrrega • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string> - <string name="user_add_user" msgid="4336657383006913022">"Afegeix un usuari"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Usuari nou"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vols suprimir el convidat?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Suprimeix"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continua"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Vols afegir un usuari nou?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar-se l\'espai.\n\nQualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"S\'ha assolit el límit d\'usuaris"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Pots afegir fins a <xliff:g id="COUNT">%d</xliff:g> usuaris.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloqueja per utilitzar"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Hi ha hagut un problema en obtenir les teves targetes; torna-ho a provar més tard"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuració de la pantalla de bloqueig"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escaneja un codi QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de treball"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode d\'avió"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Llisca per veure\'n més"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregant les recomanacions"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimèdia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Vols amagar aquesta sessió multimèdia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"La sessió multimèdia actual no es pot amagar."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignora"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Amaga"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) s\'està reproduint des de l\'aplicació <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acosta\'t a <xliff:g id="DEVICENAME">%1$s</xliff:g> per reproduir el contingut aquí"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"S\'està reproduint a <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"S\'està reproduint en aquest telèfon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"S\'ha produït un error"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string> <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index ee9a04fe2dd6..4feb8dc7fb33 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Pokud při příštím pokusu zadáte nesprávné gesto, váš pracovní profil a přidružená data budou smazána."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Pokud při příštím pokusu zadáte nesprávný PIN, váš pracovní profil a přidružená data budou smazána."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Pokud při příštím pokusu zadáte nesprávné heslo, váš pracovní profil a přidružená data budou smazána."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Příliš mnoho neplatných pokusů. Data v tomto zařízení budou smazána."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Příliš mnoho neplatných pokusů. Tento uživatel bude smazán."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Příliš mnoho neplatných pokusů. Tento pracovní profil a přidružená data budou smazána."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Zavřít"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotkněte se snímače otisků prstů"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otisku prstu"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Pomalé nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjecí dok • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string> - <string name="user_add_user" msgid="4336657383006913022">"Přidat uživatele"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nový uživatel"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstranit hosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstranit"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ano, pokračovat"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Přidat nového uživatele?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Když přidáte nového uživatele, musí si nastavit vlastní prostor.\n\nJakýkoli uživatel může aktualizovat aplikace všech ostatních uživatelů."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Bylo dosaženo limitu uživatelů"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="few">Lze přidat až <xliff:g id="COUNT">%d</xliff:g> uživatele.</item> @@ -465,8 +456,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odemknout a použít"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Při načítání karet došlo k problému, zkuste to později"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavení obrazovky uzamčení"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Naskenovat QR kód"</string> <string name="status_bar_work" msgid="5238641949837091056">"Pracovní profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Režim Letadlo"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Svůj další budík <xliff:g id="WHEN">%1$s</xliff:g> neuslyšíte"</string> @@ -797,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Přejetím prstem zobrazíte další položky"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítání doporučení"</string> <string name="controls_media_title" msgid="1746947284862928133">"Média"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Skrýt tuto mediální relaci?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Aktuální mediální relaci nelze skrýt."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Zavřít"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrýt"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> hrajte z aplikace <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -817,7 +808,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pokud zde chcete přehrávat média, přibližte se k zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Přehrávání v zařízení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Přehrávání v tomto telefonu"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Něco se pokazilo"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 43027b833267..a018f1194477 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Hvis du angiver et forkert mønster i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hvis du angiver en forkert pinkode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hvis du angiver en forkert adgangskode i næste forsøg, slettes din arbejdsprofil og de tilhørende data."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"For mange forkerte forsøg. Dataene på denne enhed slettes."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"For mange forkerte forsøg. Denne bruger slettes."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"For mange forkerte forsøg. Denne arbejdsprofil og de tilhørende data slettes."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Afvis"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sæt fingeren på fingeraftrykslæseren"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon for fingeraftryk"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader langsomt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader i dockingstation • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string> - <string name="user_add_user" msgid="4336657383006913022">"Tilføj bruger"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruger"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gæsten?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsæt"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Vil du tilføje en ny bruger?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Når du tilføjer en ny bruger, skal personen konfigurere sit område.\n\nAlle brugere kan opdatere apps for alle de andre brugere."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Grænsen for antal brugere er nået"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Du kan tilføje op til <xliff:g id="COUNT">%d</xliff:g> bruger.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås op for at bruge"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Dine kort kunne ikke hentes. Prøv igen senere."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lås skærmindstillinger"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scan QR-kode"</string> <string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Stryg for at se mere"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Indlæser anbefalinger"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medie"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Vil du skjule denne mediesession?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Den aktuelle mediesession kan ikke skjules."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Luk"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> af <xliff:g id="ARTIST_NAME">%2$s</xliff:g> afspilles via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ryk tættere på <xliff:g id="DEVICENAME">%1$s</xliff:g> for at afspille her"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspilles på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Afspilles på denne telefon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Noget gik galt"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 60bcecb93d8b..fd426819f78e 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Wenn du beim nächsten Versuch ein falsches Muster eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Wenn du beim nächsten Versuch eine falsche PIN eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Wenn du beim nächsten Versuch ein falsches Passwort eingibst, werden dein Arbeitsprofil und die zugehörigen Daten gelöscht."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Zu viele Fehlversuche. Die Daten auf diesem Gerät werden gelöscht."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Zu viele Fehlversuche. Dieser Nutzer wird vom Gerät entfernt."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Zu viele Fehlversuche. Dieses Arbeitsprofil und die zugehörigen Daten werden gelöscht."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Schließen"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Berühre den Fingerabdrucksensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerabdruck-Symbol"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird langsam geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladestation • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string> - <string name="user_add_user" msgid="4336657383006913022">"Nutzer hinzufügen"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Neuer Nutzer"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast entfernen?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Entfernen"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, weiter"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Neuen Nutzer hinzufügen?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten.\n\nJeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Nutzerlimit erreicht"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Du kannst bis zu <xliff:g id="COUNT">%d</xliff:g> Nutzer hinzufügen.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Zum Verwenden entsperren"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Beim Abrufen deiner Karten ist ein Fehler aufgetreten – bitte versuch es später noch einmal"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Einstellungen für den Sperrbildschirm"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR-Code scannen"</string> <string name="status_bar_work" msgid="5238641949837091056">"Arbeitsprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flugmodus"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Wischen, um weitere zu sehen"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medien"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Diese Mediensitzung ausblenden?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Die Mediensitzung kann nicht ausgeblendet werden."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ausblenden"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ausblenden"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> von <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wird gerade über <xliff:g id="APP_LABEL">%3$s</xliff:g> wiedergegeben"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Platziere für die Wiedergabe dein Gerät näher an „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Wird auf „<xliff:g id="DEVICENAME">%1$s</xliff:g>“ abgespielt"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Wird auf diesem Smartphone abgespielt"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Ein Fehler ist aufgetreten"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 17a54c2ad7c9..bbc2ee357ec2 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Εάν εισαγάγετε εσφαλμένο μοτίβο στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Εάν εισαγάγετε εσφαλμένο PIN στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Εάν εισαγάγετε εσφαλμένο κωδικό πρόσβασης στην επόμενη προσπάθεια, το προφίλ εργασίας σας και τα δεδομένα του θα διαγραφούν."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Πάρα πολλές ανεπιτυχείς προσπάθειες. Τα δεδομένα αυτής της συσκευής θα διαγραφούν."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Πάρα πολλές ανεπιτυχείς προσπάθειες. Αυτός ο χρήστης θα διαγραφεί."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Πάρα πολλές ανεπιτυχείς προσπάθειες. Αυτό το προφίλ εργασίας και τα δεδομένα του θα διαγραφούν."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Παράβλεψη"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Αγγίξτε τον αισθητήρα δακτυλικού αποτυπώματος"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Αργή φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Βάση φόρτισης • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string> - <string name="user_add_user" msgid="4336657383006913022">"Προσθήκη χρήστη"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Νέος χρήστης"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Κατάργηση επισκέπτη;"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Κατάργηση"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Kαλώς ορίσατε ξανά!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ναι, συνέχεια"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Προσθήκη νέου χρήστη;"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του.\n\nΟποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Συμπληρώθηκε το όριο χρηστών"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Μπορείτε να προσθέσετε έως <xliff:g id="COUNT">%d</xliff:g> χρήστες.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ξεκλείδωμα για χρήση"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Παρουσιάστηκε πρόβλημα με τη λήψη των καρτών σας. Δοκιμάστε ξανά αργότερα"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ρυθμίσεις κλειδώματος οθόνης"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Σάρωση κωδικού QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Προφίλ εργασίας"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Λειτουργία πτήσης"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Δεν θα ακούσετε το επόμενο ξυπνητήρι σας <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Σύρετε για να δείτε περισσότερα."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Φόρτωση προτάσεων"</string> <string name="controls_media_title" msgid="1746947284862928133">"Μέσα"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Απόκρυψη αυτής της περιόδου λειτουργίας μέσου;"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Αδυναμία απόκρ. τρέχουσας περιόδ. λειτουργ. μέσου."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Παράβλεψη"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Απόκρυψη"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Γίνεται αναπαραγωγή του <xliff:g id="SONG_NAME">%1$s</xliff:g> από <xliff:g id="ARTIST_NAME">%2$s</xliff:g> στην εφαρμογή <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Μετακινηθείτε πιο κοντά στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g> για αναπαραγωγή εδώ"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Αναπαραγωγή στη συσκευή <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Αναπαραγωγή σε αυτό το τηλέφωνο"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Παρουσιάστηκε κάποιο πρόβλημα"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Παρουσιάστηκε κάποιο πρόβλημα. Δοκιμάστε ξανά."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 5544a9597fae..10fcd34c547e 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> - <string name="user_add_user" msgid="4336657383006913022">"Add user"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 9a204eb5d296..6289676c6c50 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> - <string name="user_add_user" msgid="4336657383006913022">"Add user"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 5544a9597fae..10fcd34c547e 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> - <string name="user_add_user" msgid="4336657383006913022">"Add user"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 5544a9597fae..10fcd34c547e 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> - <string name="user_add_user" msgid="4336657383006913022">"Add user"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 052f175280ff..aef122a2ebc6 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"If you enter an incorrect password on the next attempt, your work profile and its data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Too many incorrect attempts. This device’s data will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Too many incorrect attempts. This user will be deleted."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Too many incorrect attempts. This work profile and its data will be deleted."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dismiss"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerprint icon"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognize face. Use fingerprint instead."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging slowly • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging Dock • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> - <string name="user_add_user" msgid="4336657383006913022">"Add user"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"New user"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start over"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yes, continue"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Add new user?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"User limit reached"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">You can add up to <xliff:g id="COUNT">%d</xliff:g> users.</item> @@ -784,9 +775,9 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Hide this media session?"</string> + <string name="controls_media_close_session" msgid="4780485355795635052">"Hide this media control for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> <string name="controls_media_active_session" msgid="3146882316024153337">"The current media session cannot be hidden."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> by <xliff:g id="ARTIST_NAME">%2$s</xliff:g> is playing from <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +795,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Move closer to <xliff:g id="DEVICENAME">%1$s</xliff:g> to play here"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Playing on <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Playing on this phone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Something went wrong"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Something went wrong. Try again."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 57996ee26e6f..4acc257db4d9 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si ingresas un patrón incorrecto en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si ingresas un PIN incorrecto en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si ingresas una contraseña incorrecta en el próximo intento, se borrarán tu perfil de trabajo y sus datos."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Hubo demasiados intentos incorrectos. Se borrarán los datos del dispositivo."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Hubo demasiados intentos incorrectos. Se borrará este usuario."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Hubo demasiados intentos incorrectos. Se borrarán este perfil de trabajo y sus datos."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Descartar"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas dactilares"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícono de huella dactilar"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lento • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Conectado y cargando • Carga completa en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> - <string name="user_add_user" msgid="4336657383006913022">"Agregar usuario"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Usuario nuevo"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"¡Hola de nuevo, invitado!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres retomar la sesión?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continuar"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"¿Agregar usuario nuevo?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Cuando agregas un nuevo usuario, esa persona debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzaste el límite de usuarios"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Puedes agregar hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de pantalla de bloqueo"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear código QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más elementos"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contenido multimedia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"¿Quieres ocultar esta sesión multimedia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"No se puede ocultar la sesión multimedia actual."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Descartar"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproducir aquí"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproduciendo en este teléfono"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Ocurrió un error"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index f4a8cf7f673e..1a621725cfbb 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si vuelves a introducir un patrón incorrecto, tu perfil de trabajo y sus datos se eliminarán."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vuelves a introducir un PIN incorrecto, tu perfil de trabajo y sus datos se eliminarán."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vuelves a introducir una contraseña incorrecta, tu perfil de trabajo y sus datos se eliminarán."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Se han producido demasiados intentos fallidos. Los datos de este dispositivo se eliminarán."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Se han producido demasiados intentos fallidos. Este usuario se eliminará."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Se han producido demasiados intentos fallidos. Este perfil de trabajo y sus datos se eliminarán."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Cerrar"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas digitales"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icono de huella digital"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de carga • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargar"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string> - <string name="user_add_user" msgid="4336657383006913022">"Añadir usuario"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nuevo usuario"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Hola de nuevo, invitado"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con la sesión?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sí, continuar"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"¿Añadir nuevo usuario?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Al añadir un nuevo usuario, este debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Has alcanzado el límite de usuarios"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Puedes añadir hasta <xliff:g id="COUNT">%d</xliff:g> usuarios.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Se ha producido un problema al obtener tus tarjetas. Inténtalo de nuevo más tarde."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ajustes de pantalla de bloqueo"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear código QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"¿Ocultar esta sesión multimedia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"La sesión multimedia no se puede ocultar."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Cerrar"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Se está reproduciendo <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Acércate a <xliff:g id="DEVICENAME">%1$s</xliff:g> para jugar aquí"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproduciendo en <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproduciendo en este dispositivo"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Se ha producido un error"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Se ha producido un error. Inténtalo de nuevo."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string> <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Control no disponible"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index b6d266c394aa..191179878bea 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Kui sisestate järgmisel katsel vale mustri, kustutatakse teie tööprofiil ja selle andmed."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Kui sisestate järgmisel katsel vale PIN-koodi, kustutatakse teie tööprofiil ja selle andmed."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Kui sisestate järgmisel katsel vale parooli, kustutatakse teie tööprofiil ja selle andmed."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Liiga palju valesid katseid. Selle seadme andmed kustutatakse."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Liiga palju valesid katseid. See kasutaja kustutatakse."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Liiga palju valesid katseid. See tööprofiil ja selle andmed kustutatakse."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Sulge"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Puudutage sõrmejäljeandurit"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Sõrmejälje ikoon"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Aeglane laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laadimisdokk • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string> - <string name="user_add_user" msgid="4336657383006913022">"Lisa kasutaja"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Uus kasutaja"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Kas eemaldada külaline?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eemalda"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Jah, jätka"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Kas lisada uus kasutaja?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi.\n\nIga kasutaja saab värskendada rakendusi kõigi kasutajate jaoks."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Kasutajate limiit on täis"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Võite lisada kuni <xliff:g id="COUNT">%d</xliff:g> kasutajat.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avage kasutamiseks"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Teie kaartide hankimisel ilmnes probleem, proovige hiljem uuesti"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukustuskuva seaded"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skannige QR-kood"</string> <string name="status_bar_work" msgid="5238641949837091056">"Tööprofiil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lennukirežiim"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Te ei kuule järgmist äratust kell <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pühkige sõrmega, et näha rohkem"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string> <string name="controls_media_title" msgid="1746947284862928133">"Meedia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Kas peita see meediaseanss?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Praegust meediaseanssi ei saa peita."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Loobu"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Peida"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> esitajalt <xliff:g id="ARTIST_NAME">%2$s</xliff:g> esitatakse rakenduses <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siin esitamiseks liigutage seadmele <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemale"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Esitatakse seadmes <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Esitatakse selles telefonis"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Midagi läks valesti"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 768c2020e5b6..3f51b06dd93b 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Hurrengo saiakeran eredua oker marrazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hurrengo saiakeran PINa oker idazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hurrengo saiakeran pasahitza oker idazten baduzu, laneko profila eta bertako datuak ezabatuko dira."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Saiakera oker gehiegi egin dituzu. Gailuko datuak ezabatu egingo dira."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Saiakera oker gehiegi egin dituzu. Erabiltzailea ezabatu egingo da."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Saiakera oker gehiegi egin dituzu. Laneko profila eta bertako datuak ezabatu egingo dira."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Baztertu"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sakatu hatz-marken sentsorea"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Hatz-markaren ikonoa"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ez da hauteman aurpegia. Erabili hatz-marka."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mantso kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oinarrian kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string> - <string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzaile bat"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gonbidatua kendu nahi duzu?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kendu"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Ongi etorri berriro, gonbidatu hori!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Saioarekin jarraitu nahi duzu?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Hasi berriro"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Bai, jarraitu"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Beste erabiltzaile bat gehitu?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Erabiltzaile bat gehitzen duzunean, erabiltzaile horrek bere eremua konfiguratu beharko du.\n\nEdozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Erabiltzaile-mugara iritsi zara"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Gehienez, <xliff:g id="COUNT">%d</xliff:g> erabiltzaile gehi ditzakezu.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desblokeatu erabiltzeko"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Arazo bat izan da txartelak eskuratzean. Saiatu berriro geroago."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Pantaila blokeatuaren ezarpenak"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Eskaneatu QR kodea"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profila"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Multimedia-saioa ezkutatu nahi duzu?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Ezin da ezkutatu multimedia-saioa."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ezkutatu"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>) ari da erreproduzitzen <xliff:g id="APP_LABEL">%3$s</xliff:g> bidez"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Gerturatu <xliff:g id="DEVICENAME">%1$s</xliff:g> gailura bertan erreproduzitzen ari dena hemen erreproduzitzeko"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> gailuan erreproduzitzen"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Telefono honetan erreproduzitzen"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Arazoren bat izan da"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 3e76c46241f8..dd6a6cbe173a 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -98,7 +98,7 @@ <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"درحال ضبط صفحهنمایش"</string> <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"درحال ضبط صفحهنمایش و صدا"</string> <string name="screenrecord_taps_label" msgid="1595690528298857649">"نمایش قسمتهای لمسشده روی صفحهنمایش"</string> - <string name="screenrecord_stop_label" msgid="72699670052087989">"توقف"</string> + <string name="screenrecord_stop_label" msgid="72699670052087989">"متوقف کردن"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"همرسانی"</string> <string name="screenrecord_save_title" msgid="1886652605520893850">"قطعه ضبطشده از صفحهنمایش ذخیره شد"</string> <string name="screenrecord_save_text" msgid="3008973099800840163">"برای مشاهده ضربه بزنید"</string> @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"اگر در تلاش بعدی الگوی نادرستی وارد کنید، دادههای نمایه کاری شما و دادههای آن حذف خواهد شد."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"اگر در تلاش بعدی پین نادرستی وارد کنید، نمایه کاری شما و دادههای آن حذف خواهند شد."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"اگر در تلاش بعدی گذرواژه نادرستی وارد کنید، نمایه کاری شما و دادههای آن حذف خواهند شد."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"تلاشهای نادرست بسیار زیادی انجام شده است. دادههای این دستگاه حذف خواهد شد."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"تلاشهای اشتباه بسیار زیادی انجام شده است. این کاربر حذف خواهد شد."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"تلاشهای اشتباه بسیار زیادی انجام شده است. این نمایه کاری و دادههای آن حذف خواهند شد."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"رد کردن"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"حسگر اثر انگشت را لمس کنید"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"نماد اثر انگشت"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string> @@ -283,7 +279,7 @@ <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC فعال است"</string> <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ضبط صفحهنمایش"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع"</string> - <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"توقف"</string> + <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"متوقف کردن"</string> <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"حالت تک حرکت"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string> <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ کردن آهسته • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • پایه شارژ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string> - <string name="user_add_user" msgid="4336657383006913022">"افزودن کاربر"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"کاربر جدید"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مهمان حذف شود؟"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"حذف"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد میگوییم!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا میخواهید جلسهتان را ادامه دهید؟"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"بله، ادامه داده شود"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"کاربر جدیدی اضافه میکنید؟"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"وقتی کاربر جدیدی اضافه میکنید آن فرد باید فضای خودش را تنظیم کند.\n\nهر کاربری میتواند برنامهها را برای همه کاربران دیگر بهروزرسانی کند."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"به تعداد مجاز تعداد کاربر رسیدهاید"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">میتوانید حداکثر <xliff:g id="COUNT">%d</xliff:g> کاربر اضافه کنید.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"برای استفاده، قفل را باز کنید"</string> <string name="wallet_error_generic" msgid="257704570182963611">"هنگام دریافت کارتها مشکلی پیش آمد، لطفاً بعداً دوباره امتحان کنید"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"تنظیمات صفحه قفل"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"اسکن رمزینه پاسخسریع"</string> <string name="status_bar_work" msgid="5238641949837091056">"نمایه کاری"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"حالت هواپیما"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"در ساعت <xliff:g id="WHEN">%1$s</xliff:g>، دیگر صدای زنگ ساعت را نمیشنوید"</string> @@ -546,7 +536,7 @@ <string name="keyboard_key_enter" msgid="8633362970109751646">"ورود"</string> <string name="keyboard_key_backspace" msgid="4095278312039628074">"پسبر"</string> <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"پخش/مکث"</string> - <string name="keyboard_key_media_stop" msgid="1509943745250377699">"توقف"</string> + <string name="keyboard_key_media_stop" msgid="1509943745250377699">"متوقف کردن"</string> <string name="keyboard_key_media_next" msgid="8502476691227914952">"بعدی"</string> <string name="keyboard_key_media_previous" msgid="5637875709190955351">"قبلی"</string> <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"عقب بردن"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"برای دیدن موارد بیشتر، تند بکشید"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"درحال بار کردن توصیهها"</string> <string name="controls_media_title" msgid="1746947284862928133">"رسانه"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"این جلسه رسانه پنهان شود؟"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"جلسه رسانه کنونی نمیتواند پنهان شود."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"رد کردن"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"پنهان کردن"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> از <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ازطریق <xliff:g id="APP_LABEL">%3$s</xliff:g> پخش میشود"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"برای پخش در اینجا، به <xliff:g id="DEVICENAME">%1$s</xliff:g> نزدیکتر شوید"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"درحال پخش در <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"درحال پخش در این تلفن"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"مشکلی رخ داد"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"مشکلی پیش آمد. دوباره امتحان کنید."</string> <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string> <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string> @@ -899,8 +890,8 @@ </plurals> <string name="fgs_dot_content_description" msgid="2865071539464777240">"اطلاعات جدید"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"برنامههای فعال"</string> - <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"توقف"</string> - <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقف شد"</string> + <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"متوقف کردن"</string> + <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"متوقف شده"</string> <string name="clipboard_edit_text_copy" msgid="770856373439969178">"کپی کردن"</string> <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"کپی شد"</string> <string name="clipboard_edit_source" msgid="9156488177277788029">"از <xliff:g id="APPNAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 3257d8b87385..758d2f0a2d17 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jos annat väärän kuvion seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jos annat väärän PIN-koodin seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jos annat väärän salasanan seuraavalla yrityskerralla, työprofiilisi ja sen data poistetaan."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Liian monta virheellistä yritystä. Laitteen data poistetaan."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Liian monta virheellistä yritystä. Tämä käyttäjä poistetaan."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Liian monta virheellistä yritystä. Tämä työprofiili ja sen data poistetaan."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ohita"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Kosketa sormenjälkitunnistinta"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Sormenjälkikuvake"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu hitaasti • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladataan telineellä • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kunnes täynnä"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string> - <string name="user_add_user" msgid="4336657383006913022">"Lisää käyttäjä"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Uusi käyttäjä"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Poistetaaanko vieras?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Poista"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Kyllä, haluan jatkaa"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Lisätäänkö uusi käyttäjä?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kun lisäät uuden käyttäjän, hänen tulee määrittää oman tilansa asetukset.\n\nKaikki käyttäjät voivat päivittää sovelluksia muille käyttäjille."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Käyttäjäraja saavutettu"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Voit lisätä korkeintaan <xliff:g id="COUNT">%d</xliff:g> käyttäjää.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Avaa lukitus ja käytä"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Korttien noutamisessa oli ongelma, yritä myöhemmin uudelleen"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lukitusnäytön asetukset"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skannaa QR-koodi"</string> <string name="status_bar_work" msgid="5238641949837091056">"Työprofiili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lentokonetila"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Et kuule seuraavaa hälytystäsi (<xliff:g id="WHEN">%1$s</xliff:g>)."</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pyyhkäise nähdäksesi lisää"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ladataan suosituksia"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Piilotetaanko median käyttökerta?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Tätä median käyttökertaa ei voi piilottaa."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ohita"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Piilota"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Asetukset"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> soittaa nyt tätä: <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Siirrä <xliff:g id="DEVICENAME">%1$s</xliff:g> lähemmäs toistaaksesi täällä"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Toistetaan: <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Toistetaan tällä puhelimella"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Tapahtui virhe"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index e91e55dd4d37..6157cc511da1 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si vous entrez un schéma incorrect à la prochaine tentative suivante, votre profil professionnel et ses données seront supprimés."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vous entrez un NIP incorrect à la prochaine tentative, votre profil professionnel et ses données seront supprimés."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vous entrez un mot de passe incorrect à la prochaine tentative suivante, votre profil professionnel et ses données seront supprimés."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Trop de tentatives incorrectes. Les données de cet appareil seront supprimées."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Trop de tentatives incorrectes. Cet utilisateur sera supprimé."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Trop de tentatives incorrectes. Ce profil professionnel et ses données seront supprimés."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Fermer"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touchez le capteur d\'empreintes digitales"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icône d\'empreinte digitale"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"En recharge lente : <xliff:g id="PERCENTAGE">%2$s</xliff:g> • Terminée <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Station de recharge • Recharge terminée dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> - <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Ajouter un utilisateur?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nTout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite d\'utilisateurs atteinte"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Vous pouvez ajouter jusqu\'à <xliff:g id="COUNT">%d</xliff:g> utilisateur.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Un problème est survenu lors de la récupération de vos cartes, veuillez réessayer plus tard"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Numériser le code QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme à <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayez l\'écran pour en afficher davantage"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Commandes multimédias"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Masquer cette session multimédia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Impossible de masquer la session multimédia actuelle"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Fermer"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecteur à partir de <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez-vous de <xliff:g id="DEVICENAME">%1$s</xliff:g> pour lire le contenu"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lecture sur ce téléphone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Un problème est survenu"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 33194aae5042..cc5dbe997c16 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Si vous dessinez un schéma incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Si vous saisissez un code incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Si vous saisissez un mot de passe incorrect lors de la prochaine tentative, votre profil professionnel et les données associées seront supprimés."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Trop de tentatives incorrectes. Les données de cet appareil vont être supprimées."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Trop de tentatives incorrectes. Ce compte utilisateur va être supprimé."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Trop de tentatives incorrectes. Ce profil professionnel et les données associées vont être supprimés."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Fermer"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Appuyez sur le lecteur d\'empreinte digitale"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icône d\'empreinte digitale"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge lente • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Station de charge • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> - <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oui, continuer"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Ajouter un utilisateur ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace.\n\nN\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite nombre utilisateurs atteinte"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Vous pouvez ajouter <xliff:g id="COUNT">%d</xliff:g> profil utilisateur.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Problème de récupération de vos cartes. Réessayez plus tard"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scanner un code QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayer l\'écran pour voir plus d\'annonces"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Masquer cette session multimédia ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Session multimédia en cours impossible à masquer."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Fermer"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> par <xliff:g id="ARTIST_NAME">%2$s</xliff:g> est en cours de lecture depuis <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Rapprochez l\'appareil pour transférer la diffusion à votre <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lecture sur <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lire sur ce téléphone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Un problème est survenu"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 52a55e7ab7fa..ce0340ecc04e 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se indicas un padrón incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se indicas un PIN incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se indicas un contrasinal incorrecto no seguinte intento, eliminaranse o teu perfil de traballo e os datos asociados."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Realizaches demasiados intentos incorrectos. Eliminaranse os datos deste dispositivo."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Realizaches demasiados intentos incorrectos. Eliminarase este usuario."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Realizaches demasiados intentos incorrectos. Eliminaranse este perfil de traballo e os datos asociados."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignorar"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca o sensor de impresión dixital"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona de impresión dixital"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Non se recoñeceu a cara. Usa a impresión dixital."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Base de carga • Carga completa dentro de <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> - <string name="user_add_user" msgid="4336657383006913022">"Engadir usuario"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuario"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Queres quitar o convidado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Si, continuar"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Engadir un usuario novo?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Cando engadas un usuario novo, este deberá configurar o seu espazo.\n\nCalquera usuario pode actualizar as aplicacións para todos os demais usuarios."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Alcanzouse o límite de usuarios"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Podes engadir ata <xliff:g id="COUNT">%d</xliff:g> usuarios.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Produciuse un problema ao obter as tarxetas. Téntao de novo máis tarde"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración da pantalla de bloqueo"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Escanear código QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de traballo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Non escoitarás a alarma seguinte <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasar o dedo para ver máis"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendacións"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contido multimedia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Queres ocultar esta sesión multimedia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Non se pode ocultar esta sesión multimedia."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Estase reproducindo <xliff:g id="SONG_NAME">%1$s</xliff:g>, de <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, en <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Achégate ao dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>) para reproducir o contido neste"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducindo contido noutro dispositivo (<xliff:g id="DEVICENAME">%1$s</xliff:g>)"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducindo contido neste teléfono"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Produciuse un erro"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 497029e8927e..19b7792bba33 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"જો તમે આગલા પ્રયત્નમાં ખોટી પૅટર્ન દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"જો તમે આગલા પ્રયત્નમાં ખોટો પિન દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"જો તમે આગલા પ્રયત્નમાં ખોટો પાસવર્ડ દાખલ કરશો, તો તમારી કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ઘણા બધા ખોટા પ્રયત્નો. આ ડિવાઇસનો ડેટા ડિલીટ કરવામાં આવશે."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ઘણા બધા ખોટા પ્રયત્નો. આ વપરાશકર્તાને ડિલીટ કરવામાં આવશે."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ઘણા બધા ખોટા પ્રયત્નો. આ કાર્યાલયની પ્રોફાઇલ અને તેનો ડેટા ડિલીટ કરવામાં આવશે."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"છોડી દો"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ફિંગરપ્રિન્ટના સેન્સરને સ્પર્શ કરો"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ફિંગરપ્રિન્ટનું આઇકન"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ધીમેથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં ચાર્જ થઈ જશે"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ડૉકથી ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં સંપૂર્ણ ચાર્જ થઈ જશે"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string> - <string name="user_add_user" msgid="4336657383006913022">"વપરાશકર્તા ઉમેરો"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"નવો વપરાશકર્તા"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"અતિથિ દૂર કરીએ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"કાઢી નાખો"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ રાખવા માંગો છો?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"હા, ચાલુ રાખો"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"નવા વપરાશકર્તાને ઉમેરીએ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિને તેમનું સ્થાન સેટ કરવાની જરૂર પડે છે.\n\nકોઈપણ વપરાશકર્તા બધા અન્ય વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"વપરાશકર્તા સંખ્યાની મર્યાદા"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">તમે <xliff:g id="COUNT">%d</xliff:g> વપરાશકર્તા સુધી ઉમેરી શકો છો.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string> <string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"લૉક સ્ક્રીનના સેટિંગ"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR કોડ સ્કૅન કરો"</string> <string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"વધુ જોવા માટે સ્વાઇપ કરો"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string> <string name="controls_media_title" msgid="1746947284862928133">"મીડિયા"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"શું આ મીડિયા સત્ર છુપાવીએ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"હાલનું મીડિયા સત્ર છુપાવી શકાતું નથી."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"છોડી દો"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"છુપાવો"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> પર <xliff:g id="ARTIST_NAME">%2$s</xliff:g>નું <xliff:g id="SONG_NAME">%1$s</xliff:g> ગીત ચાલી રહ્યું છે"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"આમાં ચલાવવા માટે ડિવાઇસને <xliff:g id="DEVICENAME">%1$s</xliff:g>ની નજીક ખસેડો"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> પર ચલાવવામાં આવી રહ્યું છે"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"આ ફોન પર ચલાવવામાં આવી રહ્યું છે"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"કંઈક ખોટું થયું"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string> <string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index d7b9f327d821..115c7d30fe60 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"अगर आप फिर से गलत पैटर्न डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"अगर आप फिर से गलत पिन डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"अगर आप फिर से गलत पासवर्ड डालते हैं, तो आपकी वर्क प्रोफ़ाइल और उसका डेटा मिटा दिया जाएगा."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"कई बार गलत कोशिशें की गई हैं. इस डिवाइस का डेटा मिटा दिया जाएगा."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"कई बार गलत कोशिशें की गई हैं. इस उपयोगकर्ता की जानकारी मिटा दी जाएगी."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"कई बार गलत कोशिशें की गई हैं. यह वर्क प्रोफ़ाइल और इसका डेटा मिटा दिया जाएगा."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"खारिज करें"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फ़िंगरप्रिंट सेंसर को छुएं"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फ़िंगरप्रिंट आइकॉन"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • धीरे चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • डॉक पर चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string> - <string name="user_add_user" msgid="4336657383006913022">"उपयोगकर्ता जोड़ें"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"नया उपयोगकर्ता"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"क्या आप मेहमान को हटाना चाहते हैं?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सत्र के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"निकालें"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"मेहमान, आपका फिर से स्वागत है!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"क्या आप अपना सत्र जारी रखना चाहते हैं?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"हां, जारी रखें"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"नया उपयोगकर्ता जोड़ें?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं, तो उसे अपनी जगह सेट करनी होती है.\n\nकोई भी उपयोगकर्ता बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"अब और उपयोगकर्ता नहीं जोड़े जा सकते"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">आप ज़्यादा से ज़्यादा <xliff:g id="COUNT">%d</xliff:g> उपयोगकर्ता जोड़ सकते हैं.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"इस्तेमाल करने के लिए, डिवाइस अनलॉक करें"</string> <string name="wallet_error_generic" msgid="257704570182963611">"आपके कार्ड की जानकारी पाने में कोई समस्या हुई है. कृपया बाद में कोशिश करें"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन की सेटिंग"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"क्यूआर कोड स्कैन करें"</string> <string name="status_bar_work" msgid="5238641949837091056">"वर्क प्रोफ़ाइल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"हवाई जहाज़ मोड"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"आपको <xliff:g id="WHEN">%1$s</xliff:g> पर अपना अगला अलार्म नहीं सुनाई देगा"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ज़्यादा देखने के लिए स्वाइप करें"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सुझाव लोड हो रहे हैं"</string> <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"क्या आप इस मीडिया सेशन को छिपाना चाहते हैं?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"मौजूदा मीडिया सेशन को छिपाया नहीं जा सकता."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"खारिज करें"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"छिपाएं"</string> <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> पर, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> का <xliff:g id="SONG_NAME">%1$s</xliff:g> चल रहा है"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"अपने डिवाइस पर मीडिया फ़ाइल ट्रांसफ़र करने के लिए, उसे <xliff:g id="DEVICENAME">%1$s</xliff:g> के पास ले जाएं"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> पर मीडिया चल रहा है"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"इस फ़ोन पर मीडिया चल रहा है"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"कोई गड़बड़ी हुई"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string> <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं है"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string> @@ -900,7 +892,7 @@ <string name="fgs_dot_content_description" msgid="2865071539464777240">"नई जानकारी"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ये ऐप्लिकेशन चालू हैं"</string> <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"बंद करें"</string> - <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"रुका हुआ है"</string> + <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"बंद है"</string> <string name="clipboard_edit_text_copy" msgid="770856373439969178">"कॉपी करें"</string> <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"कॉपी किया गया"</string> <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> से"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 77cf81422a41..10d7ab5cdd3f 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ako pri sljedećem pokušaju unesete netočan uzorak, izbrisat će se vaš poslovni profil i njegovi podaci."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ako pri sljedećem pokušaju unesete netočan PIN, izbrisat će se vaš poslovni profil i njegovi podaci."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ako pri sljedećem pokušaju unesete netočnu zaporku, izbrisat će se vaš poslovni profil i njegovi podaci."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Previše netočnih pokušaja. S uređaja će se izbrisati podaci."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Previše netočnih pokušaja. Ovaj će se korisnik izbrisati."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Previše netočnih pokušaja. Ovaj će se poslovni profil izbrisati zajedno sa svim svojim podacima."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Odbaci"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor otiska prsta"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona otiska prsta"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string> @@ -325,17 +321,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • sporo punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Priključna stanica za punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string> - <string name="user_add_user" msgid="4336657383006913022">"Dodavanje korisnika"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nastavi"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Dodati novog korisnika?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor.\n\nBilo koji korisnik može ažurirati aplikacije za sve ostale korisnike."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Dosegnuto je ograničenje korisnika"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Možete dodati najviše <xliff:g id="COUNT">%d</xliff:g> korisnika.</item> @@ -790,9 +781,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prijeđite prstom da vidite više"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Želite li sakriti medijsku sesiju?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Trenutačna medijska sesija ne može se sakriti."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odbaci"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g> reproducira se putem aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -810,7 +802,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približite se uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g> da biste na njemu reproducirali"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Reproducira se na uređaju <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Reproducira se na ovom telefonu"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Nešto nije u redu"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index f256bc14b63f..68e94b1b3bbe 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Amennyiben helytelen mintát ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Amennyiben helytelen PIN-kódot ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Amennyiben helytelen jelszót ad meg a következő kísérletnél, a rendszer törli munkaprofilját és a kapcsolódó adatokat."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Túl sok sikertelen próbálkozás. A rendszer törli az adatokat az eszközről."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Túl sok sikertelen próbálkozás. A rendszer törli ezt a felhasználót."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Túl sok sikertelen próbálkozás. A rendszer törli ezt a munkaprofilt és a kapcsolódó adatokat."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Elvetés"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Érintse meg az ujjlenyomat-érzékelőt"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ujjlenyomat ikonja"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lassú töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Töltődokk • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string> - <string name="user_add_user" msgid="4336657383006913022">"Felhasználó hozzáadása"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Új felhasználó"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Eltávolítja a vendég munkamenetet?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eltávolítás"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Igen, folytatom"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Új felhasználó hozzáadása?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját tárterületét.\n\nBármely felhasználó frissítheti az alkalmazásokat valamennyi felhasználó számára."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Maximális felhasználószám elérve"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Legfeljebb <xliff:g id="COUNT">%d</xliff:g> felhasználót adhat hozzá.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Továbbiak megtekintéséhez csúsztasson"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Javaslatok betöltése…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Média"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Elrejti ezt a média-munkamenetet?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Az aktuális média-munkamenet nem rejthető el."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Elvetés"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Elrejtés"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> <xliff:g id="SONG_NAME">%1$s</xliff:g> című száma hallható itt: <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Menjen közelebb a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközhöz, hogy itt játszhassa le a tartalmat"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Lejátszás folyamatban a(z) <xliff:g id="DEVICENAME">%1$s</xliff:g> eszközön"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Lejátszás ezen a telefonon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Hiba történt"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index a4e3b82b264b..999a37f69f3e 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Հաջորդ փորձի ժամանակ սխալ նախշ մուտքագրելու դեպքում ձեր աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Հաջորդ փորձի ժամանակ սխալ PIN կոդ մուտքագրելու դեպքում աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Հաջորդ փորձի ժամանակ սխալ գաղտնաբառ մուտքագրելու դեպքում աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Չափից շատ սխալ փորձեր են արվել։ Այս սարքի տվյալները կջնջվեն։"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Չափից շատ սխալ փորձեր են արվել։ Oգտատիրոջ պրոֆիլը կջնջվի։"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Չափից շատ սխալ փորձեր են արվել։ Աշխատանքային պրոֆիլը և դրա տվյալները կջնջվեն։"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Փակել"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Հպեք մատնահետքի սկաներին"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Մատնահետքի պատկերակ"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Դանդաղ լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում դոկ-կայանի միջոցով • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string> - <string name="user_add_user" msgid="4336657383006913022">"Ավելացնել օգտատեր"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Նոր օգտատեր"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Հեռացնե՞լ հյուրին"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր ծրագրերն ու տվյալները կջնջվեն:"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Հեռացնել"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Բարի վերադարձ, հյուր"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Շարունակե՞լ աշխատաշրջանը։"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Վերսկսել"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Այո, շարունակել"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Ավելացնե՞լ նոր օգտատեր"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Երբ նոր օգտատեր եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը:\n\nՑանկացած օգտատեր կարող է թարմացնել հավելվածները մյուս բոլոր հաշիվների համար:"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Սահմանաչափը սպառված է"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Հնարավոր է ավելացնել առավելագույնը <xliff:g id="COUNT">%d</xliff:g> օգտատեր։</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ապակողպել՝ օգտագործելու համար"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Չհաջողվեց բեռնել քարտերը։ Նորից փորձեք։"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Կողպէկրանի կարգավորումներ"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Սկանավորել QR կոդը"</string> <string name="status_bar_work" msgid="5238641949837091056">"Android for Work-ի պրոֆիլ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Ավիառեժիմ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի"</string> @@ -546,7 +536,7 @@ <string name="keyboard_key_enter" msgid="8633362970109751646">"Մուտք"</string> <string name="keyboard_key_backspace" msgid="4095278312039628074">"Հետշարժ"</string> <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"Նվագարկում/դադար"</string> - <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Դադարեցնել"</string> + <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Կանգնեցնել"</string> <string name="keyboard_key_media_next" msgid="8502476691227914952">"Հաջորդը"</string> <string name="keyboard_key_media_previous" msgid="5637875709190955351">"Նախորդը"</string> <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"Հետ անցնել"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Սահեցրեք մատը՝ ավելին իմանալու համար"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Բեռնման խորհուրդներ"</string> <string name="controls_media_title" msgid="1746947284862928133">"Մեդիա"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Թաքցնե՞լ մեդիայի աշխատաշրջանը"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Չհաջողվեց թաքցնել մեդիայի ընթացիկ աշխատաշրջանը։"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Փակել"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Թաքցնել"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Կարգավորումներ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Այժմ նվագարկվում է <xliff:g id="SONG_NAME">%1$s</xliff:g> երգը <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-ի կատարմամբ <xliff:g id="APP_LABEL">%3$s</xliff:g> հավելվածից"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ավելի մոտեցեք «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքին՝ նվագարկումը սկսելու համար"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Նվագարկվում է «<xliff:g id="DEVICENAME">%1$s</xliff:g>» սարքում"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Նվագարկվում է այս հեռախոսում"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Սխալ առաջացավ"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Սխալ առաջացավ։ Նորից փորձեք։"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string> @@ -824,7 +815,7 @@ <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string> <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Այս աշխատաշրջանը հեռարձակելու համար բացեք հավելվածը"</string> <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Անհայտ հավելված"</string> - <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Դադարեցնել հեռարձակումը"</string> + <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Կանգնեցնել հեռարձակումը"</string> <string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string> <string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string> <string name="basic_status" msgid="2315371112182658176">"Բաց զրույց"</string> @@ -899,7 +890,7 @@ </plurals> <string name="fgs_dot_content_description" msgid="2865071539464777240">"Նոր տեղեկություն"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Ակտիվ հավելվածներ"</string> - <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Դադարեցնել"</string> + <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Կանգնեցնել"</string> <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Կանգնեցված է"</string> <string name="clipboard_edit_text_copy" msgid="770856373439969178">"Պատճենել"</string> <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Պատճենվեց"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index c9ce287484ab..ba145626278d 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jika Anda memasukkan pola yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jika Anda memasukkan PIN yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jika Anda memasukkan sandi yang salah saat mencoba lagi, profil kerja dan datanya akan dihapus."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Terlalu banyak percobaan yang salah. Data perangkat ini akan dihapus."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Terlalu banyak percobaan yang salah. Pengguna ini akan dihapus."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Terlalu banyak percobaan yang salah. Profil kerja ini dan datanya akan dihapus."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Tutup"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh sensor sidik jari"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon sidik jari"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi daya dengan lambat • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi Daya dengan Dok • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string> - <string name="user_add_user" msgid="4336657383006913022">"Tambahkan pengguna"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baru"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Hapus tamu?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data di sesi ini akan dihapus."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hapus"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ya, lanjutkan"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Tambahkan pengguna baru?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruangnya sendiri.\n\nPengguna mana pun dapat mengupdate aplikasi untuk semua pengguna lain."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Batas pengguna tercapai"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Anda dapat menambahkan hingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Terjadi masalah saat mendapatkan kartu Anda, coba lagi nanti"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setelan layar kunci"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Pindai kode QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Geser untuk melihat selengkapnya"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuat rekomendasi"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Sembunyikan sesi media ini?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Sesi media aktif tidak dapat disembunyikan."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Tutup"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setelan"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sedang diputar dari <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan ke <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk memutar di sini"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Diputar di <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Diputar di ponsel ini"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Terjadi error"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string> @@ -899,7 +891,7 @@ </plurals> <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informasi baru"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplikasi aktif"</string> - <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string> + <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Hentikan"</string> <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dihentikan"</string> <string name="clipboard_edit_text_copy" msgid="770856373439969178">"Salin"</string> <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Disalin"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 78d2ecf38a18..72dc98e515bf 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ef þú slærð inn rangt mynstur í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ef þú slærð inn rangt PIN-númer í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ef þú slærð inn rangt aðgangsorð í næstu tilraun verður vinnusniðinu þínu og gögnum þess eytt."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Of margar rangar tilraunir. Gögnum tækisins verður eytt."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Of margar rangar tilraunir. Þessum notanda verður eytt."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Of margar rangar tilraunir. Þessu vinnusniði og gögnum þess verður eytt."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Loka"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Snertu fingrafaralesarann"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingrafaratákn"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hæg hleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hleður í dokku • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string> - <string name="user_add_user" msgid="4336657383006913022">"Bæta notanda við"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nýr notandi"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Fjarlægja gest?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjarlægja"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Já, halda áfram"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Bæta nýjum notanda við?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Þegar þú bætir nýjum notanda við þarf sá notandi að setja upp svæðið sitt.\n\nHvaða notandi sem er getur uppfært forrit fyrir alla aðra notendur."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Notandahámarki náð"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Þú getur bætt við allt að <xliff:g id="COUNT">%d</xliff:g> notanda.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Taktu úr lás til að nota"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Vandamál kom upp við að sækja kortin þín. Reyndu aftur síðar"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Stillingar fyrir læstan skjá"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skanna QR-kóða"</string> <string name="status_bar_work" msgid="5238641949837091056">"Vinnusnið"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flugstilling"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ekki mun heyrast í vekjaranum <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Strjúktu til að sjá meira"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Hleður tillögum"</string> <string name="controls_media_title" msgid="1746947284862928133">"Margmiðlunarefni"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Fela þessa efnislotu?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Ekki tókst að fela opna efnislotu."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Hunsa"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fela"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> með <xliff:g id="ARTIST_NAME">%2$s</xliff:g> er í spilun á <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Færðu tækið nær <xliff:g id="DEVICENAME">%1$s</xliff:g> til að spila hér"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Í spilun í <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Í spilun í þessum síma"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Eitthvað fór úrskeiðis"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 9b0f917759d3..bb3ff8f3ca5e 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se al prossimo tentativo inserirai una sequenza sbagliata, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se al prossimo tentativo inserirai un PIN sbagliato, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se al prossimo tentativo inserirai una password sbagliata, il tuo profilo di lavoro e i relativi dati verranno eliminati."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Troppi tentativi sbagliati. I dati del dispositivo verranno eliminati."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Troppi tentativi sbagliati. Questo utente verrà eliminato."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Troppi tentativi sbagliati. Questo profilo di lavoro e i relativi dati verranno eliminati."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignora"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tocca il sensore di impronte"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icona dell\'impronta"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ricarica lenta • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • In carica nel dock • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string> - <string name="user_add_user" msgid="4336657383006913022">"Aggiungi utente"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nuovo utente"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Rimuovere l\'ospite?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Rimuovi"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Ti ridiamo il benvenuto alla sessione Ospite."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sì, continua"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Aggiungere un nuovo utente?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Il nuovo utente, una volta aggiunto, deve impostare il proprio spazio.\n\nQualsiasi utente può aggiornare le app per tutti gli altri."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite di utenti raggiunto"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Puoi aggiungere fino a <xliff:g id="COUNT">%d</xliff:g> utenti.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Scorri per vedere altro"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Caricamento dei consigli"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contenuti multimediali"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Vuoi nascondere questa sessione multimediale?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Imposs. nascondere sessione multimediale corrente."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignora"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Nascondi"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> di <xliff:g id="ARTIST_NAME">%2$s</xliff:g> è in riproduzione da <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Avvicinati a <xliff:g id="DEVICENAME">%1$s</xliff:g> per riprodurre i contenuti qui"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"In riproduzione su <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"In riproduzione su questo telefono"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Si è verificato un errore"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 7dcde9cf4f5c..c33247ace5cf 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"הזנת קו ביטול נעילה שגוי בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"הזנה של קוד אימות שגוי בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"הזנת סיסמה שגויה בניסיון הבא תגרום למחיקת פרופיל העבודה והנתונים המשויכים אליו."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"נעשו יותר מדי ניסיונות שגויים. הנתונים במכשיר יימחקו."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"בוצעו יותר מדי ניסיונות שגויים. המשתמש הזה יימחק."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"נעשו יותר מדי ניסיונות שגויים. פרופיל העבודה הזה והנתונים המשויכים אליו יימחקו."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"סגירה"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"יש לגעת בחיישן טביעות האצבע"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"סמל טביעת אצבע"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • בטעינה איטית • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • אביזר העגינה בטעינה • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string> - <string name="user_add_user" msgid="4336657383006913022">"הוספת משתמש"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"משתמש חדש"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"להסיר אורח?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"הסרה"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"סשן חדש"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"כן, להמשיך"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"להוסיף משתמש חדש?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"כשמוסיפים משתמש חדש, המשתמש הזה צריך להגדיר את השטח שלו.\n\nכל משתמש יכול לעדכן אפליקציות עבור כל המשתמשים האחרים."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"הגעת למגבלת המשתמשים שניתן להוסיף"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="two">ניתן להוסיף עד <xliff:g id="COUNT">%d</xliff:g> משתמשים.</item> @@ -465,8 +456,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"יש לבטל את הנעילה כדי להשתמש"</string> <string name="wallet_error_generic" msgid="257704570182963611">"הייתה בעיה בקבלת הכרטיסים שלך. כדאי לנסות שוב מאוחר יותר"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"הגדרות מסך הנעילה"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"סריקת קוד QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את ההתראה הבאה שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -797,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"יש להחליק כדי להציג עוד פריטים"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ההמלצות בטעינה"</string> <string name="controls_media_title" msgid="1746947284862928133">"מדיה"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"להסתיר את סשן המדיה?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"לא ניתן להסתיר את סשן המדיה הנוכחי."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"סגירה"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"הסתרה"</string> <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> של <xliff:g id="ARTIST_NAME">%2$s</xliff:g> מופעל מ-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -817,7 +808,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"צריך להתקרב אל <xliff:g id="DEVICENAME">%1$s</xliff:g> כדי להפעיל כאן"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"פועלת ב-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"פועלת בטלפון הזה"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"משהו השתבש"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string> <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 956826bb5e37..181f046c8920 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"パターンをあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"PIN をあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"パスワードをあと 1 回間違えると、仕事用プロファイルと関連データが削除されます。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"間違えた回数が上限を超えました。このデバイスのデータが削除されます。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"間違えた回数が上限を超えました。このユーザーが削除されます。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"間違えた回数が上限を超えました。この仕事用プロファイルと関連データが削除されます。"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"閉じる"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"指紋認証センサーをタッチ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋アイコン"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 低速充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ホルダーで充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string> - <string name="user_add_user" msgid="4336657383006913022">"ユーザーを追加"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"新しいユーザー"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ゲストを削除しますか?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"削除"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"続行"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"新しいユーザーを追加しますか?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。\n\nすべてのユーザーは他のユーザーに代わってアプリを更新できます。"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"ユーザー数が上限に達しました"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">最大 <xliff:g id="COUNT">%d</xliff:g> 人のユーザーを追加できます。</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"スワイプすると他の構造が表示されます"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string> <string name="controls_media_title" msgid="1746947284862928133">"メディア"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"このメディア セッションを非表示にしますか?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"現在のメディア セッションは非表示にできません。"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"閉じる"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"非表示"</string> <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>(アーティスト名: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>)が <xliff:g id="APP_LABEL">%3$s</xliff:g> で再生中"</string> @@ -804,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ここで再生するには<xliff:g id="DEVICENAME">%1$s</xliff:g>に近づいてください"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>で再生しています"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"このスマートフォンで再生しています"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"エラーが発生しました"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string> <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 7ecdfd93b2c4..97417d9535c1 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"შემდეგი მცდელობისას განმბლოკავი ნიმუშის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"შემდეგი მცდელობისას PIN-კოდის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"შემდეგი მცდელობისას პაროლის არასწორად შეყვანის შემთხვევაში, თქვენი სამსახურის პროფილი და მისი მონაცემები წაიშლება."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"დაფიქსირდა ზედმეტად ბევრი არასწორი მცდელობა. შედეგად, ამ მოწყობილობის მონაცემები წაიშლება."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"დაფიქსირდა ზედმეტად ბევრი არასწორი მცდელობა. შედეგად, ეს მომხმარებელი წაიშლება."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"დაფიქსირდა ზედმეტად ბევრი არასწორი მცდელობა. შედეგად, სამსახურის ეს პროფილი და მისი მონაცემები წაიშლება."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"დახურვა"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"შეეხეთ თითის ანაბეჭდის სენსორს"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"თითის ანაბეჭდის ხატულა"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ნელა იტენება • სრულ დატენვამდე <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • დამტენი სამაგრი • დატენამდე დარჩა <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string> - <string name="user_add_user" msgid="4336657383006913022">"მომხმარებლის დამატება"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"ახალი მომხმარებელი"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"სტუმრის ამოშლა?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ამოშლა"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"სტუმარო, გვიხარია, რომ დაბრუნდით!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"გსურთ, თქვენი სესიის გაგრძელება?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ხელახლა დაწყება"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"დიახ, გავაგრძელოთ"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"დაემატოს ახალი მომხმარებელი?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის შექმნა მოუწევს.\n\nნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"მიღწეულია მომხმარებელთა ლიმიტი"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">შესაძლებელია <xliff:g id="COUNT">%d</xliff:g>-მდე მომხმარებლის დამატება.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"გამოსაყენებლად განბლოკვა"</string> <string name="wallet_error_generic" msgid="257704570182963611">"თქვენი ბარათების მიღებისას პრობლემა წარმოიშვა. ცადეთ ხელახლა მოგვიანებით"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ჩაკეტილი ეკრანის პარამეტრები"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR კოდის სკანირება"</string> <string name="status_bar_work" msgid="5238641949837091056">"სამსახურის პროფილი"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"თვითმფრინავის რეჟიმი"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ვერ გაიგონებთ მომდევნო მაღვიძარას <xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"გადაფურცლეთ მეტის სანახავად"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"მიმდინარეობს რეკომენდაციების ჩატვირთვა"</string> <string name="controls_media_title" msgid="1746947284862928133">"მედია"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"დაიმალოს მედიის ეს სესია?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"მედიის მიმდინარე სესიის დამალვა შეუძლებელია."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"დახურვა"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"დამალვა"</string> <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"პარამეტრები"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g>, <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, უკრავს <xliff:g id="APP_LABEL">%3$s</xliff:g>-დან"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"მიუახლოვდით <xliff:g id="DEVICENAME">%1$s</xliff:g>-ს მისი მეშვეობით დასაკრავად"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"მიმდინარეობს დაკვრა <xliff:g id="DEVICENAME">%1$s</xliff:g>-ზე"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"მიმდინარეობს დაკვრა ამ ტელეფონზე"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"რაღაც შეცდომაა"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"რაღაც შეცდომა მოხდა. ცადეთ ხელახლა."</string> <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 85283de03b1c..713201b2ded6 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Келесі әрекет кезінде қате өрнек енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Келесі әрекет кезінде қате PIN кодын енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Келесі әрекет кезінде қате құпия сөз енгізсеңіз, жұмыс профиліңіз бен оның деректері жойылады."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Тым көп қате әрекет жасалды. Бұл құрылғылардың деректері жойылады."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Тым көп қате әрекет жасалды. Бұл пайдаланушы жойылады."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Тым көп қате әрекет жасалды. Бұл жұмыс профилі мен оның деректері жойылады."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Жабу"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Саусақ ізін оқу сканерін түртіңіз"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Саусақ ізі белгішесі"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Баяу зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Қондыру станциясында зарядталуда • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string> - <string name="user_add_user" msgid="4336657383006913022">"Пайдаланушы қосу"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Жаңа пайдаланушы"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Қонақты жою керек пе?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Алып тастау"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Иә, жалғастыру"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Жаңа пайдаланушы қосылсын ба?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Жаңа пайдаланушыны қосқанда, сол адам өз кеңістігін реттеуі керек.\n\nКез келген пайдаланушы барлық басқа пайдаланушылар үшін қолданбаларды жаңарта алады."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Пайдаланушылар саны шегіне жетті"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> пайдаланушыға дейін енгізуге болады.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Пайдалану үшін құлыпты ашу"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Карталарыңыз алынбады, кейінірек қайталап көріңіз."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Экран құлпының параметрлері"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR кодын сканерлеу"</string> <string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Келесі <xliff:g id="WHEN">%1$s</xliff:g> дабылыңызды есітпейсіз"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Толығырақ ақпарат алу үшін сырғытыңыз."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мультимедиа"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Бұл мультимедиа сеансы жасырылсын ба?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Ағымдағы мультимедиа сеансын жасыру мүмкін емес."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Жабу"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жасыру"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> қолданбасында <xliff:g id="ARTIST_NAME">%2$s</xliff:g> орындайтын \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" әні ойнатылуда."</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Осы жерде ойнау үшін <xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысына жақындаңыз"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> құрылғысында ойнатылуда."</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Осы телефонда ойнатылуда."</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Бірдеңе дұрыс болмады."</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару виджеті қолжетімсіз"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 9e527e4a04c6..9ca2645b2a75 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ប្រសិនបើអ្នកបញ្ចូលលំនាំមិនត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូលលើកក្រោយ កម្រងព័ត៌មានការងាររបស់អ្នក និងទិន្នន័យរបស់កម្រងព័ត៌មាននេះនឹងត្រូវបានលុប។"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ប្រសិនបើអ្នកបញ្ចូលកូដ PIN មិនត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូលលើកក្រោយ កម្រងព័ត៌មានការងាររបស់អ្នក និងទិន្នន័យរបស់កម្រងព័ត៌មាននេះនឹងត្រូវបានលុប។"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ប្រសិនបើអ្នកបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូលលើកក្រោយ កម្រងព័ត៌មានការងាររបស់អ្នក និងទិន្នន័យរបស់កម្រងព័ត៌មាននេះនឹងត្រូវបានលុប។"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ដោយសារមានការព្យាយាមដោះសោមិនត្រឹមត្រូវច្រើនដងពេក ទិន្នន័យរបស់ឧបករណ៍នេះនឹងត្រូវបានលុប។"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ដោយសារមានការព្យាយាមដោះសោមិនត្រឹមត្រូវច្រើនដងពេក អ្នកប្រើប្រាស់នេះនឹងត្រូវបានដកចេញ។"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ដោយសារមានការព្យាយាមដោះសោមិនត្រឹមត្រូវច្រើនដងពេក កម្រងព័ត៌មានការងារនេះ និងទិន្នន័យរបស់វានឹងត្រូវបានលុប។"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ច្រានចោល"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ប៉ះឧបករណ៍ចាប់ស្នាមម្រាមដៃ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"រូបស្នាមម្រាមដៃ"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្មយឺត • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ឧបករណ៍ភ្ជាប់សាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ទៀត"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរអ្នកប្រើ"</string> - <string name="user_add_user" msgid="4336657383006913022">"បញ្ចូលអ្នកប្រើ"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"អ្នកប្រើថ្មី"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ដកភ្ញៀវចេញឬ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ដកចេញ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"សូមស្វាគមន៍ការត្រឡប់មកវិញ, ភ្ញៀវ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"តើអ្នកចង់បន្តវគ្គរបស់អ្នកទេ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើមសាជាថ្មី"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"បាទ/ចាស បន្ត"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"បញ្ចូលអ្នកប្រើថ្មីឬ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"នៅពេលអ្នកបញ្ចូលអ្នកប្រើថ្មី អ្នកប្រើនោះត្រូវរៀបចំកន្លែងរបស់គេ។\n\nអ្នកប្រើណាក៏អាចដំឡើងកំណែកម្មវិធីសម្រាប់អ្នកប្រើទាំងអស់ផ្សេងទៀតបានដែរ។"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"បានឈានដល់ចំនួនកំណត់អ្នកប្រើប្រាស់"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">អ្នកអាចបញ្ចូលអ្នកប្រើប្រាស់បានរហូតដល់ <xliff:g id="COUNT">%d</xliff:g> នាក់។</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ដោះសោដើម្បីប្រើប្រាស់"</string> <string name="wallet_error_generic" msgid="257704570182963611">"មានបញ្ហាក្នុងការទាញយកកាតរបស់អ្នក សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ការកំណត់អេក្រង់ចាក់សោ"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"ស្កេនកូដ QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"ប្រវត្តិរូបការងារ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ពេលជិះយន្តហោះ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"អូសដើម្បីមើលច្រើនទៀត"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"កំពុងផ្ទុកការណែនាំ"</string> <string name="controls_media_title" msgid="1746947284862928133">"មេឌៀ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"លាក់វគ្គមេឌៀនេះឬ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"មិនអាចលាក់វគ្គមេឌៀបច្ចុប្បន្នបានទេ។"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ច្រានចោល"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"លាក់"</string> <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ច្រៀងដោយ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> កំពុងចាក់ពី <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"រំកិលឱ្យកាន់តែជិត <xliff:g id="DEVICENAME">%1$s</xliff:g> ដើម្បីចាក់នៅទីនេះ"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"កំពុងចាក់នៅលើ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"កំពុងចាក់នៅលើទូរសព្ទនេះ"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"មានអ្វីមួយខុសប្រក្រតី"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"មានអ្វីមួយខុសប្រក្រតី។ សូមព្យាយាមម្ដងទៀត។"</string> <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string> <string name="controls_error_removed" msgid="6675638069846014366">"រកមិនឃើញទេ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាចគ្រប់គ្រងបានទេ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index ce0ca0e62f2f..afa9df47b352 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪ್ಯಾಟರ್ನ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪಿನ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪಾಸ್ವರ್ಡ್ ನಮೂದಿಸಿದರೆ, ನಿಮ್ಮ ಉದ್ಯೋಗದ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಸಾಧನದ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಬಳಕೆದಾರರನ್ನು ಅಳಿಸಲಾಗುವುದು."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ಹಲವಾರು ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಈ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಮತ್ತು ಅದರ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ವಜಾಗೊಳಿಸಿ"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಐಕಾನ್"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ಸಮಯದಲ್ಲಿ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ಡಾಕ್ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ದಲ್ಲಿ ಚಾರ್ಜ್ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string> - <string name="user_add_user" msgid="4336657383006913022">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"ಹೊಸ ಬಳಕೆದಾರರು"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ತೆಗೆದುಹಾಕಿ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ಹೌದು, ಮುಂದುವರಿಸಿ"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸುವುದೇ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"ನೀವು ಒಬ್ಬ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸ್ಥಾಪಿಸಬೇಕಾಗುತ್ತದೆ.\n\nಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಬಹುದು."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"ಬಳಕೆದಾರರ ಮಿತಿ ತಲುಪಿದೆ"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">ನೀವು <xliff:g id="COUNT">%d</xliff:g> ಬಳಕೆದಾರರವರೆಗೆ ಸೇರಿಸಬಹುದು.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ಬಳಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> <string name="wallet_error_generic" msgid="257704570182963611">"ನಿಮ್ಮ ಕಾರ್ಡ್ಗಳನ್ನು ಪಡೆಯುವಾಗ ಸಮಸ್ಯೆ ಉಂಟಾಗಿದೆ, ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ಲಾಕ್ ಸ್ಕ್ರ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ನಿಮ್ಮ ಮುಂದಿನ <xliff:g id="WHEN">%1$s</xliff:g> ಅಲಾರಮ್ ಅನ್ನು ನೀವು ಆಲಿಸುವುದಿಲ್ಲ"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ಇನ್ನಷ್ಟು ನೋಡಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ಶಿಫಾರಸುಗಳು ಲೋಡ್ ಆಗುತ್ತಿವೆ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ಮಾಧ್ಯಮ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ಈ ಮಾಧ್ಯಮ ಸೆಶನ್ ಅನ್ನು ಮರೆಮಾಡಬೇಕೆ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"ಪ್ರಸ್ತುತ ಮಾಧ್ಯಮ ಸೆಶನ್ ಅನ್ನು ಮರೆಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ವಜಾಗೊಳಿಸಿ"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ಮರೆಮಾಡಿ"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ಅವರ <xliff:g id="SONG_NAME">%1$s</xliff:g> ಹಾಡನ್ನು <xliff:g id="APP_LABEL">%3$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ಇಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು <xliff:g id="DEVICENAME">%1$s</xliff:g> ಸಮೀಪಕ್ಕೆ ಹೋಗಿ"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ಈ ಫೋನ್ನಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತಿದೆ"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"ಏನೋ ತಪ್ಪಾಗಿದೆ"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"ಏನೋ ತಪ್ಪಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string> @@ -900,7 +891,7 @@ <string name="fgs_dot_content_description" msgid="2865071539464777240">"ಹೊಸ ಮಾಹಿತಿ"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ಸಕ್ರಿಯ ಆ್ಯಪ್ಗಳು"</string> <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ನಿಲ್ಲಿಸಿ"</string> - <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ನಿಲ್ಲಿಸಿದೆ"</string> + <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ನಿಲ್ಲಿಸಲಾಗಿದೆ"</string> <string name="clipboard_edit_text_copy" msgid="770856373439969178">"ನಕಲಿಸಿ"</string> <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"ನಕಲಿಸಲಾಗಿದೆ"</string> <string name="clipboard_edit_source" msgid="9156488177277788029">"<xliff:g id="APPNAME">%1$s</xliff:g> ನಿಂದ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 8705e7105385..8ec281ddff63 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"다음번 시도에서 잘못된 패턴을 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"다음번 시도에서 잘못된 PIN을 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"다음번 시도에서 잘못된 비밀번호를 입력하면 직장 프로필 및 관련 데이터가 삭제됩니다."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"잘못된 시도 횟수가 너무 많습니다. 이 기기의 데이터가 삭제됩니다."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"잘못된 시도 횟수가 너무 많습니다. 이 사용자가 삭제됩니다."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"잘못된 시도 횟수가 너무 많습니다. 이 직장 프로필 및 관련 데이터가 삭제됩니다."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"닫기"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"지문 센서를 터치하세요."</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"지문 아이콘"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 저속 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 충전 거치대 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string> - <string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"게스트를 삭제하시겠습니까?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"삭제"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 진행"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"계속 진행"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"신규 사용자를 추가할까요?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"추가된 새로운 사용자는 자신의 공간을 설정해야 합니다.\n\n사용자라면 누구든 다른 사용자를 위해 앱을 업데이트할 수 있습니다."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"사용자 제한 도달"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">사용자를 <xliff:g id="COUNT">%d</xliff:g>명까지 추가할 수 있습니다.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"잠금 해제하여 사용"</string> <string name="wallet_error_generic" msgid="257704570182963611">"카드를 가져오는 중에 문제가 발생했습니다. 나중에 다시 시도해 보세요."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"잠금 화면 설정"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR 코드 스캔"</string> <string name="status_bar_work" msgid="5238641949837091056">"직장 프로필"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"비행기 모드"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>에 다음 알람을 들을 수 없습니다."</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"자세히 보려면 스와이프하세요."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string> <string name="controls_media_title" msgid="1746947284862928133">"미디어"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"이 미디어 세션을 숨기시겠습니까?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"현재 미디어 세션은 숨길 수 없습니다."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"닫기"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"숨기기"</string> <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>에서 <xliff:g id="ARTIST_NAME">%2$s</xliff:g>의 <xliff:g id="SONG_NAME">%1$s</xliff:g> 재생 중"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"현재 기기에서 재생하려면 <xliff:g id="DEVICENAME">%1$s</xliff:g>에 더 가까이 이동합니다."</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>에서 재생 중"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"휴대전화에서 재생 중"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"문제가 발생했습니다."</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string> <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 6187f3a27c6c..f21367922e9b 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Эгер графикалык ачкычты дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Эгер PIN кодду дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Эгер сырсөздү дагы бир жолу туура эмес киргизсеңиз, жумуш профилиңиз жана андагы маалыматтын баары өчөт."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Өтө көп жолу жаңылдыңыз. Бул түзмөктөгү дайын-даректер өчүрүлөт."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Өтө көп жолу жаңылдыңыз. Бул колдонуучу өчүрүлөт."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Өтө көп жолу жаңылдыңыз. Бул жумуш профили жана андагы маалымат өчүрүлөт."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Жабуу"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Манжа изинин сенсорун басыңыз"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Манжа изинин сүрөтчөсү"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Жай кубатталууда • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Кубаттоо догу • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string> - <string name="user_add_user" msgid="4336657383006913022">"Колдонуучу кошуу"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Жаңы колдонуучу"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Конокту алып саласызбы?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана маалыматтар өчүрүлөт."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Өчүрүү"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ооба, уланта берели"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Жаңы колдонуучу кошосузбу?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Жаңы колдонуучу кошулганда, ал өз мейкиндигин түзүп алышы керек.\n\nКолдонмолорду бир колдонуучу жаңыртканда, ал калган бардык колдонуучулар үчүн да жаңырат."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Дагы колдонуучу кошууга болбойт"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> колдонуучуга чейин кошууга болот.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Колдонуу үчүн кулпусун ачыңыз"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Кыйытмаларды алууда ката кетти. Бир аздан кийин кайталап көрүңүз."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Кулпуланган экран жөндөөлөрү"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR кодун скандоо"</string> <string name="status_bar_work" msgid="5238641949837091056">"Жумуш профили"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Учак режими"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> боло турган кийинки эскертмени укпайсыз"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Дагы көрүү үчүн экранды сүрүп коюңуз"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Бул медиа сеансы жашырылсынбы?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Учурдагы медиа сеансын жашыруу мүмкүн эмес."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Жабуу"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жашыруу"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ыры (аткаруучу: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) <xliff:g id="APP_LABEL">%3$s</xliff:g> колдонмосунан ойнотулуп жатат"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Бул жерде ойнотуу үчүн <xliff:g id="DEVICENAME">%1$s</xliff:g> түзмөгүнө жакындатыңыз"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> аркылуу ойнотулууда"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Ушул телефондо ойнотулууда"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Бир жерден ката кетти"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Башкара албайсыз"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 3343bcfa0a53..354adc32cc87 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ຫາກທ່ານໃສ່ຣູບແບບຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ຫາກທ່ານໃສ່ລະຫັດ PIN ຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ຫາກທ່ານໃສ່ລະຫັດຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກຂອງທ່ານ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ພະຍາຍາມປົດລັອກບໍ່ສຳເລັດຫຼາຍເທື່ອເກີນໄປ. ອຸປະກອນນີ້ຈະຖືກລຶບຂໍ້ມູນອອກ."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ພະຍາຍາມປົດລັອກບໍ່ສຳເລັດຫຼາຍເທື່ອເກີນໄປ. ຜູ້ໃຊ້ນີ້ຈະຖືກລຶບຂໍ້ມູນອອກ."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ພະຍາຍາມປົດລັອກບໍ່ສຳເລັດຫຼາຍເທື່ອເກີນໄປ. ໂປຣໄຟລ໌ບ່ອນເຣັດວຽກ ແລະ ຂໍ້ມູນຂອງມັນຈະຖືກລຶບອອກ."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ປິດໄວ້"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມື"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ໄອຄອນລາຍນິ້ວມື"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບຊ້າ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟຜ່ານດັອກ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string> - <string name="user_add_user" msgid="4336657383006913022">"ເພີ່ມຜູ້ໃຊ້"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"ຜູ່ໃຊ້ໃໝ່"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ລຶບແຂກບໍ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯແລະຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ລຶບ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນດີຕ້ອນຮັບກັບມາ, ຜູ້ຢ້ຽມຢາມ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານຕ້ອງການສືບຕໍ່ເຊດຊັນຂອງທ່ານບໍ່?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ຕົກລົງ, ດຳເນີນການຕໍ່"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"ເພີ່ມຜູ້ໃຊ້ໃໝ່ບໍ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"ເມື່ອທ່ານເພີ່ມຜູ້ໃຊ້ໃໝ່, ຜູ້ໃຊ້ນັ້ນຈະຕ້ອງຕັ້ງຄ່າພື້ນທີ່ບ່ອນຈັດເກັບຂໍ້ມູນຂອງລາວ.\n\nຜູ້ໃຊ້ທຸກຄົນສາມາດອັບເດດແອັບຂອງຜູ້ໃຊ້ຄົນອື່ນທັງໝົດໄດ້."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"ຮອດຂີດຈຳກັດຜູ້ໃຊ້ແລ້ວ"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">ທ່ານສາມາດເພີ່ມໄດ້ສູງສຸດ <xliff:g id="COUNT">%d</xliff:g> ຄົນ.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ປົດລັອກເພື່ອໃຊ້"</string> <string name="wallet_error_generic" msgid="257704570182963611">"ເກີດບັນຫາໃນການໂຫຼດບັດຂອງທ່ານ, ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ການຕັ້ງຄ່າໜ້າຈໍລັອກ"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"ສະແກນລະຫັດ QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ໂໝດເຮືອບິນ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ທ່ານຈະບໍ່ໄດ້ຍິນສຽງໂມງປ <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ປັດເພື່ອເບິ່ງເພີ່ມເຕີມ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ກຳລັງໂຫຼດຄຳແນະນຳ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ມີເດຍ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ເຊື່ອງເຊດຊັນມີເດຍນີ້ບໍ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"ບໍ່ສາມາດເຊື່ອງເຊດຊັນມີເດຍປັດຈຸບັນໄດ້."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ປິດໄວ້"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ເຊື່ອງ"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ການຕັ້ງຄ່າ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ໂດຍ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ກຳລັງຫຼິ້ນຈາກ <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ກະລຸນາຍ້າຍເຂົ້າໃກ້ <xliff:g id="DEVICENAME">%1$s</xliff:g> ເພື່ອຫຼິ້ນຢູ່ບ່ອນນີ້"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"ກຳລັງຫຼິ້ນຢູ່ <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ກຳລັງຫຼິ້ນຢູ່ໂທລະສັບນີ້"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"ມີບາງຢ່າງຜິດພາດເກີດຂຶ້ນ"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 547d250895ef..4fb8399303b2 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jei kitu bandymu nupiešite netinkamą atrakinimo piešinį, darbo profilis ir jo duomenys bus ištrinti."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jei kitu bandymu įvesite netinkamą PIN kodą, darbo profilis ir jo duomenys bus ištrinti."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jei kitu bandymu įvesite netinkamą slaptažodį, darbo profilis ir jo duomenys bus ištrinti."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Per daug netinkamų bandymų. Šio įrenginio duomenys bus ištrinti."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Per daug netinkamų bandymų. Šis naudotojas bus ištrintas."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Per daug netinkamų bandymų. Šis darbo profilis ir jo duomenys bus ištrinti."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Atsisakyti"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Palieskite piršto antspaudo jutiklį"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Piršto antspaudo piktograma"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lėtai įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Įkraunama doke • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string> - <string name="user_add_user" msgid="4336657383006913022">"Pridėti naudotoją"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Naujas naudotojas"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Pašalinti svečią?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Pašalinti"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Taip, tęsti"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Pridėti naują naudotoją?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo erdvę.\n\nBet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Pasiekta naudotojų riba"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Galite pridėti iki <xliff:g id="COUNT">%d</xliff:g> naudotojo.</item> @@ -465,8 +456,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Atrakinti, kad būtų galima naudoti"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Gaunant korteles kilo problema, bandykite dar kartą vėliau"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Užrakinimo ekrano nustatymai"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodo nuskaitymas"</string> <string name="status_bar_work" msgid="5238641949837091056">"Darbo profilis"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lėktuvo režimas"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Negirdėsite kito signalo <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -797,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Perbraukite, kad peržiūrėtumėte daugiau"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Įkeliamos rekomendacijos"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medija"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Slėpti šį medijos seansą?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Dabartinio medijos seanso negalima paslėpti."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Atsisakyti"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Slėpti"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nustatymai"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> – „<xliff:g id="SONG_NAME">%1$s</xliff:g>“ leidžiama iš „<xliff:g id="APP_LABEL">%3$s</xliff:g>“"</string> @@ -817,7 +808,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Perkelkite arčiau „<xliff:g id="DEVICENAME">%1$s</xliff:g>“, kad būtų galima leisti čia"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Leidžiama įrenginyje „<xliff:g id="DEVICENAME">%1$s</xliff:g>“"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Leidžiama šiame telefone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Kažkas ne taip"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 5e79f75557be..5265e50f3b07 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ja nākamajā mēģinājumā ievadīsiet nepareizu kombināciju, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ja nākamajā mēģinājumā ievadīsiet nepareizu PIN, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ja nākamajā mēģinājumā ievadīsiet nepareizu paroli, jūsu darba profils un ar to saistītie dati tiks dzēsti."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Pārāk daudz neveiksmīgu mēģinājumu. Dati šajā ierīcē tiks dzēsti."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Pārāk daudz neveiksmīgu mēģinājumu. Šis lietotājs tiks dzēsts."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Pārāk daudz neveiksmīgu mēģinājumu. Šis darba profils un ar to saistītie dati tiks dzēsti."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Nerādīt"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pieskarieties pirksta nospieduma sensoram"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Pirksta nospieduma ikona"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string> @@ -325,17 +321,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lēnā uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Notiek uzlāde dokā • Līdz pilnai uzlādei atlicis: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string> - <string name="user_add_user" msgid="4336657383006913022">"Lietotāja pievienošana"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Jauns lietotājs"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vai noņemt viesi?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Noņemt"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Jā, turpināt"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Vai pievienot jaunu lietotāju?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kad pievienosiet jaunu lietotāju, viņam būs jāizveido savs profils.\n\nIkviens lietotājs var atjaunināt lietotnes citu lietotāju vietā."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Sasniegts lietotāju ierobežojums"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="zero">Varat pievienot ne vairāk kā <xliff:g id="COUNT">%d</xliff:g> lietotājus.</item> @@ -462,8 +453,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lai izmantotu, atbloķējiet ekrānu"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Ienesot jūsu kartes, radās problēma. Lūdzu, vēlāk mēģiniet vēlreiz."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Bloķēšanas ekrāna iestatījumi"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR koda skenēšana"</string> <string name="status_bar_work" msgid="5238641949837091056">"Darba profils"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lidojuma režīms"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nākamais signāls (<xliff:g id="WHEN">%1$s</xliff:g>) netiks atskaņots."</string> @@ -791,9 +781,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Velciet, lai skatītu citus vienumus"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Notiek ieteikumu ielāde"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multivide"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Vai paslēpt šo multivides sesiju?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Pašreizējo multivides sesiju nevar paslēpt."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Nerādīt"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Paslēpt"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Iestatījumi"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tiek atskaņots fails “<xliff:g id="SONG_NAME">%1$s</xliff:g>” (izpildītājs: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) no lietotnes <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> @@ -811,7 +802,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Pārvietojieties tuvāk ierīcei “<xliff:g id="DEVICENAME">%1$s</xliff:g>”, lai atskaņotu šeit"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Notiek atskaņošana ierīcē <xliff:g id="DEVICENAME">%1$s</xliff:g>."</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Notiek atskaņošana šajā tālrunī"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Radās problēma"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 0bde00b24b63..bbf7d346109a 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако внесете погрешна шема при следниот обид, работниот профил и неговите податоци ќе се избришат."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако внесете погрешен PIN при следниот обид, работниот профил и неговите податоци ќе се избришат."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако внесете погрешна лозинка при следниот обид, работниот профил и неговите податоци ќе се избришат."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Премногу погрешни обиди. Податоците на уредов ќе се избришат."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Премногу погрешни обиди. Корисникот ќе се избрише."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Премногу погрешни обиди. Работниот профил и неговите податоци ќе се избришат."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Отфрли"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Допрете го сензорот за отпечатоци"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона за отпечаток"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни бавно • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни на док • Полн за <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string> - <string name="user_add_user" msgid="4336657383006913022">"Додај корисник"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Нов корисник"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се отстрани гостинот?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Отстрани"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продолжи"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Да се додаде нов корисник?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Кога додавате нов корисник, тоа лице треба да го постави својот простор.\n\nСекој корисник може да ажурира апликации за сите други корисници."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнато ограничување на корисник"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Може да додадете најмногу <xliff:g id="COUNT">%d</xliff:g> корисник.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Отклучете за да користите"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Имаше проблем при преземањето на картичките. Обидете се повторно подоцна"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Поставки за заклучен екран"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Скенирајте QR-код"</string> <string name="status_bar_work" msgid="5238641949837091056">"Работен профил"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Авионски режим"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Нема да го слушнете следниот аларм <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Повлечете за да видите повеќе"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string> <string name="controls_media_title" msgid="1746947284862928133">"Аудиовизуелни содржини"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Да се сокрие аудиовизуелнава сесија?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Аудиовизуелнава сесија не може да се сокрие."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Отфрли"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сокриј"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Поставки"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> од <xliff:g id="ARTIST_NAME">%2$s</xliff:g> е пуштено на <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближете се до <xliff:g id="DEVICENAME">%1$s</xliff:g> за да пуштите тука"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пуштено на <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Пуштено на овој телефон"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Нешто тргна наопаку"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Нешто не е во ред. Обидете се повторно."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string> @@ -899,7 +890,7 @@ </plurals> <string name="fgs_dot_content_description" msgid="2865071539464777240">"Нови информации"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни апликации"</string> - <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Крај"</string> + <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Запри"</string> <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Запрено"</string> <string name="clipboard_edit_text_copy" msgid="770856373439969178">"Копирај"</string> <string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Копирано"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index e7ccae0997c6..c08c1bc3e189 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പാറ്റേൺ നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പിൻ നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പാസ്വേഡ് നൽകിയാൽ, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഉപകരണത്തിലെ ഡാറ്റ ഇല്ലാതാക്കപ്പെടും."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഉപയോക്താവ് ഇല്ലാതാക്കപ്പെടും."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ഒരുപാട് തെറ്റായ ശ്രമങ്ങൾ. ഈ ഔദ്യോഗിക പ്രൊഫൈലും അതിന്റെ ഡാറ്റയും ഇല്ലാതാക്കപ്പെടും."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ഡിസ്മിസ് ചെയ്യുക"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ഫിംഗർപ്രിന്റ് സെൻസർ സ്പർശിക്കുക"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • പതുക്കെ ചാർജ് ചെയ്യുന്നു • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ചാർജിംഗ് ഡോക്ക് • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string> - <string name="user_add_user" msgid="4336657383006913022">"ഉപയോക്താവിനെ ചേര്ക്കുക"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"പുതിയ ഉപയോക്താവ്"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"അതിഥിയെ നീക്കംചെയ്യണോ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"നീക്കംചെയ്യുക"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥി, വീണ്ടും സ്വാഗതം!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"അതെ, തുടരുക"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"പുതിയ ഉപയോക്താവിനെ ചേർക്കണോ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"നിങ്ങൾ പുതിയൊരു ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തിക്ക് അവരുടെ ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്.\n\nമറ്റ് എല്ലാ ഉപയോക്താക്കൾക്കുമായി ഏതൊരു ഉപയോക്താവിനും ആപ്പുകൾ അപ്ഡേറ്റ് ചെയ്യാനാവും."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"ഉപയോക്തൃ പരിധി എത്തി"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">നിങ്ങൾക്ക് <xliff:g id="COUNT">%d</xliff:g> ഉപയോക്താക്കളെ വരെ ചേർക്കാനാവും.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ഉപയോഗിക്കാൻ അൺലോക്ക് ചെയ്യുക"</string> <string name="wallet_error_generic" msgid="257704570182963611">"നിങ്ങളുടെ കാർഡുകൾ ലഭ്യമാക്കുന്നതിൽ ഒരു പ്രശ്നമുണ്ടായി, പിന്നീട് വീണ്ടും ശ്രമിക്കുക"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ലോക്ക് സ്ക്രീൻ ക്രമീകരണം"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR കോഡ് സ്കാൻ ചെയ്യുക"</string> <string name="status_bar_work" msgid="5238641949837091056">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ഫ്ലൈറ്റ് മോഡ്"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-നുള്ള നിങ്ങളുടെ അടുത്ത അലാറം കേൾക്കില്ല"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"കൂടുതൽ കാണാൻ സ്വൈപ്പ് ചെയ്യുക"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"നിർദ്ദേശങ്ങൾ ലോഡ് ചെയ്യുന്നു"</string> <string name="controls_media_title" msgid="1746947284862928133">"മീഡിയ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ഈ മീഡിയ സെഷൻ മറയ്ക്കണോ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"നിലവിലെ മീഡിയ സെഷൻ മറയ്ക്കാനാകില്ല."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ഡിസ്മിസ് ചെയ്യുക"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"മറയ്ക്കുക"</string> <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ക്രമീകരണം"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> എന്ന ആർട്ടിസ്റ്റിന്റെ <xliff:g id="SONG_NAME">%1$s</xliff:g> എന്ന ഗാനം <xliff:g id="APP_LABEL">%3$s</xliff:g> ആപ്പിൽ പ്ലേ ചെയ്യുന്നു"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ഇവിടെ പ്ലേ ചെയ്യാൻ <xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിന് അടുത്തേക്ക് നീക്കുക"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ഈ ഫോണിൽ പ്ലേ ചെയ്യുന്നു"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"എന്തോ കുഴപ്പമുണ്ടായി"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"എന്തോ കുഴപ്പമുണ്ടായി. വീണ്ടും ശ്രമിക്കുക."</string> <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string> @@ -894,8 +885,8 @@ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ടൈൽ ചേർക്കരുത്"</string> <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"ഉപയോക്താവിനെ തിരഞ്ഞെടുക്കൂ"</string> <plurals name="fgs_manager_footer_label" formatted="false" msgid="9091110396713032871"> - <item quantity="other">സജീവമായ <xliff:g id="COUNT_1">%s</xliff:g> ആപ്പുകൾ</item> - <item quantity="one">സജീവമായ <xliff:g id="COUNT_0">%s</xliff:g> ആപ്പ്</item> + <item quantity="other"><xliff:g id="COUNT_1">%s</xliff:g> സജീവ ആപ്പുകൾ</item> + <item quantity="one"><xliff:g id="COUNT_0">%s</xliff:g> സജീവ ആപ്പ്</item> </plurals> <string name="fgs_dot_content_description" msgid="2865071539464777240">"പുതിയ വിവരങ്ങൾ"</string> <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"സജീവമായ ആപ്പുകൾ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index b136674ea9d7..daea5d8a0189 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Та дараагийн оролдлогоор буруу хээ оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Та дараагийн оролдлогоор буруу ПИН оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Та дараагийн оролдлогоор буруу нууц үг оруулбал таны ажлын профайлыг өгөгдөлтэй нь цуг устгах болно."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Түгжээг хэт олон удаа буруу оруулсан тул энэ төхөөрөмжийн өгөгдлийг устгах болно."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Түгжээг хэт олон удаа буруу оруулсан тул энэ хэрэглэгчийг устгах болно."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Түгжээг хэт олон удаа буруу оруулсан тул энэ ажлын профайл, түүний өгөгдлийн устгах болно."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Хаах"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Хурууны хээ мэдрэгчид хүрэх"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Хурууны хээний дүрс тэмдэг"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Удаан цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Цэнэглэх холбогч • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string> - <string name="user_add_user" msgid="4336657383006913022">"Хэрэглэгч нэмэх"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Шинэ хэрэглэгч"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Зочныг хасах уу?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Хасах"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Эргэн тавтай морилно уу!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Тийм, үргэлжлүүлэх"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Шинэ хэрэглэгч нэмэх үү?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Та шинэ хэрэглэгч нэмбэл тухайн хүн өөрийн профайлыг тохируулах шаардлагатай.\n\nАль ч хэрэглэгч бүх хэрэглэгчийн аппуудыг шинэчлэх боломжтой."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Хэрэглэгчийн хязгаарт хүрсэн"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Та <xliff:g id="COUNT">%d</xliff:g> хүртэлх хэрэглэгч нэмэх боломжтой.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Илүү ихийг харахын тулд шударна уу"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Зөвлөмжүүдийг ачаалж байна"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Энэ медиа харилцан үйлдлийг нуух уу?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Одоогийн медиа харилцан үйлдлийг нуух боломжгүй."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Хаах"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Нуух"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> дээр тоглуулж буй <xliff:g id="ARTIST_NAME">%2$s</xliff:g>-н <xliff:g id="SONG_NAME">%1$s</xliff:g>"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Энд тоглуулахын тулд <xliff:g id="DEVICENAME">%1$s</xliff:g>-д ойртоно уу"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> дээр тоглуулж байна"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Энэ утсан дээр тоглуулж байна"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Алдаа гарлаа"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Алдаа гарлаа. Дахин оролдоно уу."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 721368a04ccd..7e499ec3ee3d 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"तुम्ही पुढील प्रयत्नात चुकीचा पॅटर्न एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"तुम्ही पुढील प्रयत्नात चुकीचा पिन एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"तुम्ही पुढील प्रयत्नात चुकीचा पासवर्ड एंटर केल्यास, तुमची कार्य प्रोफाइल आणि तिचा डेटा हटवला जाईल."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"बरेच चुकीचे प्रयत्न. या डिव्हाइसचा डेटा हटवला जाईल."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"बरेच चुकीचे प्रयत्न. हा वापरकर्ता हटवला जाईल."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"बरेच चुकीचे प्रयत्न. ही कार्य प्रोफाइल आणि त्यामधील डेटा हटवला जाईल."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"डिसमिस करा"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिंट सेन्सरला स्पर्श करा"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फिंगरप्रिंट आयकन"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • हळू चार्ज होत आहे • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्जिंग डॉक • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string> - <string name="user_add_user" msgid="4336657383006913022">"वापरकर्ता जोडा"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"नवीन वापरकर्ता"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथी काढायचे?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अॅप्स आणि डेटा हटवला जाईल."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"काढा"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथी, तुमचे पुन्हा स्वागत आहे!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"येथून सुरू करा"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"होय, सुरू ठेवा"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"नवीन वापरकर्ता जोडायचा?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"तुम्ही एक नवीन वापरकर्ता जोडता तेव्हा, त्या व्यक्तीने त्यांचे स्थान सेट करणे आवश्यक असते.\n\nकोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अॅप्स अपडेट करू शकतो."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"वापरकर्ता मर्यादा गाठली"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">तुम्ही <xliff:g id="COUNT">%d</xliff:g> वापरकर्त्यांपर्यंत जोडू शकता.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"वापरण्यासाठी अनलॉक करा"</string> <string name="wallet_error_generic" msgid="257704570182963611">"तुमची कार्ड मिळवताना समस्या आली, कृपया नंतर पुन्हा प्रयत्न करा"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"लॉक स्क्रीन सेटिंग्ज"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR कोड स्कॅन करा"</string> <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"अधिक पाहण्यासाठी स्वाइप करा"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"शिफारशी लोड करत आहे"</string> <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"हे मीडिया सेशन लपवायचे आहे का?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"सध्याचे मीडिया सेशन लपवू शकत नाही."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"डिसमिस करा"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लपवा"</string> <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग्ज"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> मध्ये <xliff:g id="ARTIST_NAME">%2$s</xliff:g> चे <xliff:g id="SONG_NAME">%1$s</xliff:g> प्ले होत आहे"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"येथे प्ले करण्यासाठी <xliff:g id="DEVICENAME">%1$s</xliff:g> च्या जवळ जा"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> वर प्ले केला जात आहे"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"या फोनवर प्ले होत आहे"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"काहीतरी चूक झाली"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"काहीतरी चूक झाली. पुन्हा प्रयत्न करा."</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string> <string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index b34a312abac7..f0e48d43a8e3 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jika anda memasukkan corak yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jika anda memasukkan PIN yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jika anda memasukkan kata laluan yang salah pada percubaan seterusnya, profil kerja anda dan data profil itu akan dipadamkan."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Terlalu banyak percubaan yang salah. Data peranti ini akan dipadamkan."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Terlalu banyak percubaan yang salah. Pengguna ini akan dipadamkan."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Terlalu banyak percubaan yang salah. Profil kerja ini dan data profil itu akan dipadamkan."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ketepikan"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh penderia cap jari"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon cap jari"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan perlahan • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas dengan Dok • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string> - <string name="user_add_user" msgid="4336657383006913022">"Tambah pengguna"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baharu"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alih keluar tetamu?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alih keluar"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ya, teruskan"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Tambah pengguna baharu?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Apabila anda menambah pengguna baharu, orang itu perlu menyediakan ruang mereka.\n\nMana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Had pengguna dicapai"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Anda boleh menambah sehingga <xliff:g id="COUNT">%d</xliff:g> pengguna.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Terdapat masalah sewaktu mendapatkan kad anda. Sila cuba sebentar lagi"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Tetapan skrin kunci"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Imbas kod QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mod pesawat"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar penggera yang seterusnya <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Leret untuk melihat selanjutnya"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuatkan cadangan"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Sembunyikan sesi media ini?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Sesi media semasa tidak dapat disembunyikan."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Tolak"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> oleh <xliff:g id="ARTIST_NAME">%2$s</xliff:g> dimainkan daripada <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Dekatkan dengan <xliff:g id="DEVICENAME">%1$s</xliff:g> untuk bermain di sini"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Dimainkan pada <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Dimainkan pada telefon ini"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Ralat telah berlaku"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Kesilapan telah berlaku. Cuba lagi."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index b1b2ceb9b77a..2d764e5529a2 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"မှားယွင်းသည့် ပုံစံကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"မှားယွင်းသည့် ပင်နံပါတ်ကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"မှားယွင်းသည့် စကားဝှက်ကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက သင်၏အလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"မှားယွင်းသည့် အကြိမ်ရေ အလွန်များနေပါပြီ။ ဤစက်၏ ဒေတာကို ဖျက်လိုက်ပါမည်။"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"မှားယွင်းသည့် အကြိမ်ရေ အလွန်များနေပါပြီ။ ဤအသုံးပြုသူကို ဖျက်လိုက်ပါမည်။"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"မှားယွင်းသည့် အကြိမ်ရေ အလွန်များနေပါပြီ။ ဤအလုပ်ပရိုဖိုင်နှင့် ၎င်း၏ ဒေတာကို ဖျက်လိုက်ပါမည်။"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ပယ်ရန်"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"လက်ဗွေအာရုံခံကိရိယာကို တို့ပါ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"လက်ဗွေ သင်္ကေတ"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • နှေးကွေးစွာ အားသွင်းနေသည် • အားပြည့်ရန် <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> လိုသည်"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • အားသွင်းအထိုင် • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> တွင် ပြည့်မည်"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string> - <string name="user_add_user" msgid="4336657383006913022">"အသုံးပြုသူ ထည့်ရန်"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"အသုံးပြုသူ အသစ်"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ဧည့်သည်ကို ဖယ်မလား။"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ဖယ်ထုတ်ပါ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ဧည့်သည်ကို ပြန်လည် ကြိုဆိုပါသည်။"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်၏ စက်ရှင်ကို ဆက်လုပ်လိုပါသလား။"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ပြန်စပါ"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ဆက်လုပ်ပါ"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"အသုံးပြုသူအသစ်ကို ထည့်မလား။"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"သင်ထည့်လိုက်သော အသုံးပြုသူအသစ်သည် ၎င်း၏နေရာကို သတ်မှတ်စီစဉ်ရန် လိုအပ်သည်။\n\nမည်သည့်အသုံးပြုသူမဆို ကျန်သူများအားလုံးအတွက် အက်ပ်များကို အပ်ဒိတ်လုပ်ပေးနိုင်သည်။"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"အသုံးပြုသူ အကန့်အသတ် ပြည့်သွားပါပြီ"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">အသုံးပြုသူ <xliff:g id="COUNT">%d</xliff:g> ဦးအထိ ထည့်နိုင်သည်။</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"သုံးရန် လော့ခ်ဖွင့်ပါ"</string> <string name="wallet_error_generic" msgid="257704570182963611">"သင်၏ကတ်များ ရယူရာတွင် ပြဿနာရှိနေသည်၊ နောက်မှ ထပ်စမ်းကြည့်ပါ"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"လော့ခ်မျက်နှာပြင် ဆက်တင်များ"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ကုဒ် စကင်ဖတ်ခြင်း"</string> <string name="status_bar_work" msgid="5238641949837091056">"အလုပ် ပရိုဖိုင်"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"လေယာဉ်ပျံမုဒ်"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> ၌သင့်နောက်ထပ် နှိုးစက်ကို ကြားမည်မဟုတ်ပါ"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုကြည့်ရန် ပွတ်ဆွဲပါ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string> <string name="controls_media_title" msgid="1746947284862928133">"မီဒီယာ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ဤမီဒီယာစက်ရှင်ကို ဝှက်မလား။"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"လက်ရှိ မီဒီယာစက်ရှင်ကို ဝှက်၍မရပါ။"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ပယ်ရန်"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ဖျောက်ထားမည်"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ဆက်တင်များ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> ၏ <xliff:g id="SONG_NAME">%1$s</xliff:g> ကို <xliff:g id="APP_LABEL">%3$s</xliff:g> တွင် ဖွင့်ထားသည်"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ဤနေရာတွင်ဖွင့်ရန် <xliff:g id="DEVICENAME">%1$s</xliff:g> အနီးသို့တိုးပါ"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> တွင် ဖွင့်နေသည်"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ဤဖုန်းတွင် ဖွင့်နေသည်"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"တစ်ခုခုမှားသွားသည်"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်မှု မရနိုင်ပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 745454cc6e9b..04e4b94bc167 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Hvis du oppgir feil mønster på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Hvis du skriver inn feil PIN-kode på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Hvis du skriver inn feil passord på neste forsøk, slettes jobbprofilen din og tilknyttede data."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"For mange mislykkede forsøk. Dataene på denne enheten blir slettet."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"For mange mislykkede forsøk. Denne brukeren blir slettet."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"For mange mislykkede forsøk. Denne jobbprofilen og tilknyttede data blir slettet."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Avvis"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Trykk på fingeravtrykkssensoren"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon for fingeravtrykk"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader sakte • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ladedokk • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string> - <string name="user_add_user" msgid="4336657383006913022">"Legg til brukere"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruker"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gjesten?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle appene og all informasjon i denne økten slettes."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsett"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Vil du legge til en ny bruker?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område.\n\nAlle brukere kan oppdatere apper for alle andre brukere."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Grensen for antall brukere er nådd"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Du kan legge til opptil <xliff:g id="COUNT">%d</xliff:g> brukere.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås opp for å bruke"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Det oppsto et problem med henting av kortene. Prøv igjen senere"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Innstillinger for låseskjermen"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skann QR-koden"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work-profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flymodus"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Du hører ikke neste innstilte alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Sveip for å se flere"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laster inn anbefalinger"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medier"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Vil du skjule denne medieøkten?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Den nåværende medieøkten kan ikke skjules."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Lukk"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> av <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spilles av fra <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytt deg nærmere <xliff:g id="DEVICENAME">%1$s</xliff:g> for å spille av her"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spilles av på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Spilles av på denne telefonen"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Noe gikk galt"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index bfe29aa5a26e..c0d272dbd30b 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"तपाईंले अर्को पटक पनि गलत ढाँचा प्रविष्टि गर्नुभयो भने यो कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"तपाईंले अर्को पटक पनि गलत PIN प्रविष्टि गर्नुभयो भने तपाईंको कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"तपाईंले अर्को पटक पनि गलत पासवर्ड प्रविष्टि गर्नुभयो भने तपाईंको कार्य प्रोफाइल र त्यहाँको डेटा मेटाइने छ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"अनलक गर्ने अत्यधिक गलत प्रयासहरू भए। यो डिभाइसको डेटा मेटाइने छ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"अनलक गर्ने अत्यधिक गलत प्रयासहरू भए। यो प्रयोगकर्तालाई हटाइने छ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"अनलक गर्ने अत्यधिक गलत प्रयासहरू भए। यो कार्यलयको प्रोफाइल र यसको डेटा मेटाइने छ।"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"हटाउनुहोस्"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिन्ट सेन्सरमा छुनुहोस्"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"फिंगरप्रिन्ट जनाउने आइकन"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • बिस्तारै चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • डक चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा पूरै चार्ज हुन्छ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string> - <string name="user_add_user" msgid="4336657383006913022">"प्रयोगकर्ता थप्नुहोस्"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"नयाँ प्रयोगकर्ता"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथि हटाउने हो?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"हटाउनुहोस्"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"तपाईंलाई फेरि स्वागत छ, अतिथि"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"हो, जारी राख्नुहोस्"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"नयाँ प्रयोगकर्ता थप्ने हो?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"जब तपाईँले नयाँ प्रयोगकर्ता थप्नुहुन्छ, त्यस प्रयोगकर्ताले आफ्नो स्थान स्थापना गर्न पर्ने छ।\n\nसबै प्रयोगकर्ताले अरू प्रयोगकर्ताका एपहरू अपडेट गर्न सक्छन्।"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"प्रयोगकर्ताको सीमा पुग्यो"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">तपाईं अधिकतम <xliff:g id="COUNT">%d</xliff:g> प्रयोगहरू मात्र थप्न सक्नुहुन्छ।</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"थप हेर्न स्वाइप गर्नुहोस्"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सिफारिसहरू लोड गर्दै"</string> <string name="controls_media_title" msgid="1746947284862928133">"मिडिया"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"यो मिडिया सत्र लुकाउने हो?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"हालको मिडिया सत्र लुकाउन मिल्दैन।"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"हटाउनुहोस्"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लुकाउनुहोस्"</string> <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिङ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> को <xliff:g id="SONG_NAME">%1$s</xliff:g> बोलको गीत <xliff:g id="APP_LABEL">%3$s</xliff:g> मा बज्दै छ"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"तपाईं यहाँ प्ले गर्न चाहनुहुन्छ भने आफ्नो डिभाइसलाई <xliff:g id="DEVICENAME">%1$s</xliff:g> नजिकै लैजानुहोस्"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> मा प्ले गरिँदै छ"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"यो फोनमा प्ले गरिँदै छ"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"केही चिज गडबड भयो"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"केही चिज गडबड भयो। फेरि प्रयास गर्नुहोस्।"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string> <string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 0f49b75a06db..0fd747e2c18a 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Als je bij de volgende poging een onjuist patroon opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Als je bij de volgende poging een onjuiste pincode opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Als je bij de volgende poging een onjuist wachtwoord opgeeft, worden je werkprofiel en de bijbehorende gegevens verwijderd."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Te veel onjuiste pogingen. De gegevens van dit apparaat worden verwijderd."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Te veel onjuiste pogingen. Deze gebruiker wordt verwijderd."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Te veel onjuiste pogingen. Dit werkprofiel en de bijbehorende gegevens worden verwijderd."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Sluiten"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak de vingerafdruksensor aan"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Vingerafdrukpictogram"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Langzaam opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplaaddock • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string> - <string name="user_add_user" msgid="4336657383006913022">"Gebruiker toevoegen"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nieuwe gebruiker"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast verwijderen?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwijderen"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, doorgaan"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Nieuwe gebruiker toevoegen?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Als je een nieuwe gebruiker toevoegt, moet die persoon zijn eigen profiel instellen.\n\nElke gebruiker kan apps updaten voor alle andere gebruikers."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Gebruikerslimiet bereikt"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Je kunt maximaal <xliff:g id="COUNT">%d</xliff:g> gebruikers toevoegen.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Er is een probleem opgetreden bij het ophalen van je kaarten. Probeer het later opnieuw."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Instellingen voor vergrendelscherm"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR-code scannen"</string> <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe om meer te zien"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Aanbevelingen laden"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Deze mediasessie verbergen?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"De huidige mediasessie kan niet worden verborgen."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Sluiten"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Verbergen"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> van <xliff:g id="ARTIST_NAME">%2$s</xliff:g> wordt afgespeeld via <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ga dichter bij <xliff:g id="DEVICENAME">%1$s</xliff:g> staan om hier af te spelen"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Afspelen op <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Afspelen op deze telefoon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Er is iets misgegaan"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Er is iets misgegaan. Probeer het opnieuw."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index ed1fbbccdbe0..fb371032251b 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ ପାଟର୍ନ ପ୍ରବେଶ କଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଏବଂ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ PIN ଲେଖିଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଏବଂ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ ପାସୱାର୍ଡ ଲେଖିଲେ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଓ ଏହାର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପ୍ରଚେଷ୍ଟା। ଏହି ଡିଭାଇସର ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପ୍ରଚେଷ୍ଟା। ଏହି ଉପଯୋଗକର୍ତ୍ତା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପ୍ରଚେଷ୍ଟା। ଏହି ୱାର୍କ ପ୍ରୋଫାଇଲ୍ ଏବଂ ଏହାର ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ଖାରଜ କରନ୍ତୁ"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ଟିପଚିହ୍ନ ସେନସର୍କୁ ଛୁଅଁନ୍ତୁ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଧୀରେ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଡକରୁ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍ ବଦଳାନ୍ତୁ"</string> - <string name="user_add_user" msgid="4336657383006913022">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ଅତିଥିଙ୍କୁ କାଢ଼ିଦେବେ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"କାଢ଼ିଦିଅନ୍ତୁ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ସେସନ୍ ଜାରି ରଖିବାକୁ ଚାହାଁନ୍ତି କି?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ହଁ, ଜାରି ରଖନ୍ତୁ"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"ନୂତନ ଉପଯୋଗକର୍ତ୍ତା ଯୋଗ କରିବେ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"ଆପଣ ଜଣେ ନୂଆ ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କଲେ,ତାଙ୍କୁ ସ୍ପେସ୍ ସେଟ୍ ଅପ୍ କରିବାକୁ ପଡ଼ିବ। \n \n ଅନ୍ୟ ସମସ୍ତ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଯେ କୌଣସି ଉପଯୋଗକର୍ତ୍ତା ଆପଗୁଡ଼ିକୁ ଅପଡେଟ୍ କରିପାରିବେ।"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"ଉପଯୋଗକର୍ତ୍ତା ସୀମାରେ ପହଞ୍ଚିଛି"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">କେବଳ <xliff:g id="COUNT">%d</xliff:g> ଉପଯୋଗକର୍ତ୍ତା ହିଁ ତିଆରି କରିହେବ।</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ବ୍ୟବହାର କରିବାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string> <string name="wallet_error_generic" msgid="257704570182963611">"ଆପଣଙ୍କ କାର୍ଡଗୁଡ଼ିକ ପାଇବାରେ ଏକ ସମସ୍ୟା ହୋଇଥିଲା। ଦୟାକରି ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ସ୍କ୍ରିନ୍ ଲକ୍ ସେଟିଂସ୍"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR କୋଡ ସ୍କାନ କରନ୍ତୁ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ଅଧିକ ଦେଖିବାକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string> <string name="controls_media_title" msgid="1746947284862928133">"ମିଡିଆ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ଏହି ମିଡିଆ ସେସନକୁ ଲୁଚାଇବେ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"ବର୍ତ୍ତମାନର ମିଡିଆ ସେସନକୁ ଲୁଚାଯାଇପାରିବ ନାହିଁ।"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ଖାରଜ କରନ୍ତୁ"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ଲୁଚାନ୍ତୁ"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g>ରୁ <xliff:g id="ARTIST_NAME">%2$s</xliff:g>ଙ୍କ <xliff:g id="SONG_NAME">%1$s</xliff:g> ଚାଲୁଛି"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ଏଠାରେ ଚଲାଇବା ପାଇଁ <xliff:g id="DEVICENAME">%1$s</xliff:g>ର ପାଖକୁ ମୁଭ କରନ୍ତୁ"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>ରେ ଚାଲୁଛି"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ଏହି ଫୋନରେ ଚାଲୁଛି"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"କିଛି ତ୍ରୁଟି ହୋଇଛି"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index beda96084ddd..1a35402c9e2c 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪੈਟਰਨ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪਿੰਨ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪਾਸਵਰਡ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਹ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਇਸਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ਖਾਰਜ ਕਰੋ"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਪ੍ਰਤੀਕ"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਡੌਕ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string> - <string name="user_add_user" msgid="4336657383006913022">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ਕੀ ਮਹਿਮਾਨ ਹਟਾਉਣਾ ਹੈ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿੱਚ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ਹਟਾਓ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ਮਹਿਮਾਨ, ਫਿਰ ਤੁਹਾਡਾ ਸੁਆਗਤ ਹੈ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ਕੀ ਤੁਸੀਂ ਆਪਣਾ ਸੈਸ਼ਨ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ਹਾਂ, ਜਾਰੀ ਰੱਖੋ"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"ਕੀ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨਾ ਹੈ?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸਥਾਪਤ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।\n\nਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਨ ਦੀ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">ਤੁਸੀਂ <xliff:g id="COUNT">%d</xliff:g> ਤੱਕ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ।</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ਵਰਤਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string> <string name="wallet_error_generic" msgid="257704570182963611">"ਤੁਹਾਡੇ ਕਾਰਡ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆਈ, ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ਲਾਕ ਸਕ੍ਰੀਨ ਸੈਟਿੰਗਾਂ"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR ਕੋਡ ਸਕੈਨ ਕਰੋ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ਤੁਸੀਂ <xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ ਆਪਣਾ ਅਗਲਾ ਅਲਾਰਮ ਨਹੀਂ ਸੁਣੋਗੇ"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ਹੋਰ ਦੇਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ਮੀਡੀਆ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ਕੀ ਇਹ ਮੀਡੀਆ ਸੈਸ਼ਨ ਲੁਕਾਉਣਾ ਹੈ?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"ਮੌਜੂਦਾ ਮੀਡੀਆ ਸੈਸ਼ਨ ਲੁਕਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ਖਾਰਜ ਕਰੋ"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ਲੁਕਾਓ"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ਤੋਂ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> ਦਾ <xliff:g id="SONG_NAME">%1$s</xliff:g> ਚੱਲ ਰਿਹਾ ਹੈ"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ਇੱਥੇ ਚਲਾਉਣ ਲਈ <xliff:g id="DEVICENAME">%1$s</xliff:g> ਦੇ ਨੇੜੇ ਜਾਓ"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ਇਸ ਫ਼ੋਨ \'ਤੇ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index a2f94fc657ca..b56215d71723 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jeśli następnym razem podasz nieprawidłowy wzór, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jeśli następnym razem podasz nieprawidłowy kod PIN, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jeśli następnym razem podasz nieprawidłowe hasło, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Zbyt wiele nieudanych prób. Dane na urządzeniu zostaną usunięte."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Zbyt wiele nieudanych prób. Użytkownik zostanie usunięty."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Zbyt wiele nieudanych prób. Profil służbowy i powiązane z nim dane zostaną usunięte."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Zamknij"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknij czytnika linii papilarnych"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona odcisku palca"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wolne ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie na stacji dokującej • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string> - <string name="user_add_user" msgid="4336657383006913022">"Dodaj użytkownika"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nowy użytkownik"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Usunąć gościa?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Usuń"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, Gościu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Tak, kontynuuj"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Dodać nowego użytkownika?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil.\n\nKażdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Osiągnięto limit użytkowników"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="few">Możesz dodać maksymalnie <xliff:g id="COUNT">%d</xliff:g> użytkowników.</item> @@ -465,8 +456,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odblokuj, aby użyć"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Podczas pobierania kart wystąpił problem. Spróbuj ponownie później."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Ustawienia ekranu blokady"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Zeskanuj kod QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil służbowy"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Tryb samolotowy"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nie usłyszysz swojego następnego alarmu <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -797,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Przesuń palcem, by zobaczyć więcej"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Ukryć tę sesję multimediów?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Nie można ukryć tej sesji multimediów."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Odrzuć"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ukryj"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ustawienia"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Aplikacja <xliff:g id="APP_LABEL">%3$s</xliff:g> odtwarza utwór <xliff:g id="SONG_NAME">%1$s</xliff:g> (<xliff:g id="ARTIST_NAME">%2$s</xliff:g>)"</string> @@ -817,7 +808,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Zbliż do urządzenia <xliff:g id="DEVICENAME">%1$s</xliff:g>, aby na nim odtwarzać"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Odtwarzam na ekranie <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Odtwarzam na tym telefonie"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Coś poszło nie tak"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index adc33a7ecd11..219fd7fa66b5 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se você informar um padrão incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se você informar um PIN incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se você informar uma senha incorreta na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Excesso de tentativas incorretas. Os dados deste dispositivo serão excluídos."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Excesso de tentativas incorretas. O usuário será excluído."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Excesso de tentativas incorretas. Este perfil de trabalho e os dados dele serão excluídos."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dispensar"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando na base • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> - <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Adicionar novo usuário?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Ocultar a sessão de mídia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Não é possível ocultar a sessão de mídia atual."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Mídia aberta neste smartphone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Algo deu errado"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 79f33fb5fcc1..01cfbbb8aafb 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se introduzir um padrão incorreto na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se introduzir um PIN incorreto na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se introduzir uma palavra-passe incorreta na tentativa seguinte, o seu perfil de trabalho e os respetivos dados serão eliminados."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Demasiadas tentativas incorretas. Os dados deste dispositivo serão eliminados."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Demasiadas tentativas incorretas. Este utilizador será eliminado."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Demasiadas tentativas incorretas. Este perfil de trabalho e os respetivos dados serão eliminados."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ignorar"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressões digitais."</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar lentamente • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar na estação de ancoragem • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string> - <string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover o convidado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, convidado!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Adicionar um novo utilizador?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço.\n\nQualquer utilizador pode atualizar apps para todos os outros utilizadores."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de utilizadores alcançado"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para utilizar"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente novamente mais tarde."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Definições do ecrã de bloqueio"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Leia o código QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avião"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize rapidamente para ver mais."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Pretende ocultar esta sessão de multimédia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Não pode ocultar a sessão de multimédia atual."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> em reprodução a partir da app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para reproduzir aqui"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"A reproduzir no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"A reproduzir neste telemóvel"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Algo correu mal"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Algo correu mal. Tente novamente."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index adc33a7ecd11..219fd7fa66b5 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Se você informar um padrão incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Se você informar um PIN incorreto na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Se você informar uma senha incorreta na próxima tentativa, seu perfil de trabalho e os dados dele serão excluídos."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Excesso de tentativas incorretas. Os dados deste dispositivo serão excluídos."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Excesso de tentativas incorretas. O usuário será excluído."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Excesso de tentativas incorretas. Este perfil de trabalho e os dados dele serão excluídos."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Dispensar"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ícone de impressão digital"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando na base • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> - <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Sim, continuar"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Adicionar novo usuário?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Quando você adiciona um novo usuário, essa pessoa precisa configurar o próprio espaço.\n\nQualquer usuário pode atualizar apps para os demais usuários."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Limite de usuários atingido"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">É possível adicionar até <xliff:g id="COUNT">%d</xliff:g> usuário.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Ocultar a sessão de mídia?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Não é possível ocultar a sessão de mídia atual."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Tocando <xliff:g id="SONG_NAME">%1$s</xliff:g> de <xliff:g id="ARTIST_NAME">%2$s</xliff:g> no app <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Aproxime-se do dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g> para abrir a mídia aqui"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Mídia aberta no dispositivo <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Mídia aberta neste smartphone"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Algo deu errado"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Algo deu errado. Tente novamente."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index f57aa7195b84..5d789b85cce4 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Dacă la următoarea încercare introduceți un model incorect, profilul de serviciu și datele sale vor fi șterse."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Dacă la următoarea încercare introduceți un cod PIN incorect, profilul de serviciu și datele sale vor fi șterse."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Dacă la următoarea încercare introduceți o parolă incorectă, profilul de serviciu și datele sale vor fi șterse."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Prea multe încercări incorecte. Datele de pe acest dispozitiv vor fi șterse."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Prea multe încercări incorecte. Acest utilizator va fi șters."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Prea multe încercări incorecte. Acest profil de serviciu și datele sale vor fi șterse."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Închideți"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Atingeți senzorul de amprente"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Pictograma amprentă"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosiți amprenta."</string> @@ -325,17 +321,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Se încarcă lent • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Suport de încărcare • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Comutați între utilizatori"</string> - <string name="user_add_user" msgid="4336657383006913022">"Adăugați un utilizator"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Utilizator nou"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ștergeți invitatul?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ștergeți"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, continuați"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Adăugați un utilizator nou?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOrice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Ați atins limita de utilizatori"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="few">Puteți adăuga maximum <xliff:g id="COUNT">%d</xliff:g> utilizatori.</item> @@ -462,8 +453,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Deblocați pentru a folosi"</string> <string name="wallet_error_generic" msgid="257704570182963611">"A apărut o problemă la preluarea cardurilor. Încercați din nou mai târziu"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setările ecranului de blocare"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scanați codul QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nu veți auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -791,9 +781,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Glisați pentru a vedea mai multe"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Ascundeți sesiunea media?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Sesiunea media actuală nu se poate ascunde."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Închideți"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ascunde"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se redă în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -811,7 +802,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Mergeți mai aproape de <xliff:g id="DEVICENAME">%1$s</xliff:g> ca să redați acolo"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Se redă pe acest telefon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"A apărut o eroare"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index de09d7680330..5a261d0e2a65 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Если вы неправильно введете графический ключ ещё раз, ваш рабочий профиль и его данные будут удалены."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Если вы неправильно введете PIN-код ещё раз, ваш рабочий профиль и его данные будут удалены."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Если вы неправильно введете пароль ещё раз, ваш рабочий профиль и его данные будут удалены."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Слишком много неудачных попыток. С устройства будут удалены все данные."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Слишком много неудачных попыток. Этот пользователь будет удален."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Слишком много неудачных попыток. Этот рабочий профиль и его данные будут удалены."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Закрыть"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Прикоснитесь к сканеру отпечатков пальцев."</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок отпечатка пальца"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Медленная зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка от док-станции • Ещё <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string> - <string name="user_add_user" msgid="4336657383006913022">"Добавить пользователя"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Новый пользователь"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Удалить аккаунт гостя?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Удалить"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продолжить"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Добавить пользователя?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Когда вы добавите пользователя, ему потребуется настроить профиль.\n\nЛюбой пользователь устройства может обновлять приложения для всех аккаунтов."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнут лимит"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Можно добавить не более <xliff:g id="COUNT">%d</xliff:g> пользователя.</item> @@ -797,9 +788,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Проведите по экрану, чтобы увидеть больше"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Скрыть этот мультимедийный сеанс?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Этот мультимедийный сеанс невозможно скрыть."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Скрыть"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скрыть"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Воспроизводится медиафайл \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\" (исполнитель: <xliff:g id="ARTIST_NAME">%2$s</xliff:g>) из приложения \"<xliff:g id="APP_LABEL">%3$s</xliff:g>\"."</string> @@ -817,7 +809,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Для воспроизведения на этом устройстве подойдите ближе к другому (<xliff:g id="DEVICENAME">%1$s</xliff:g>)."</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Воспроизводится на устройстве \"<xliff:g id="DEVICENAME">%1$s</xliff:g>\"."</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Воспроизводится на этом телефоне."</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Произошла ошибка."</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index cdb0896a3fab..d6c26f229d2f 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"ඔබ ඊළඟ උත්සාහයේදී වැරදි රටාවක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"ඔබ ඊළඟ උත්සාහයේදී වැරදි PIN එකක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"ඔබ ඊළඟ උත්සාහයේදී වැරදි මුරපදයක් ඇතුළු කළහොත්, ඔබේ කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"වැරදි උත්සාහයන් ඉතා වැඩි ගණනකි. මෙම උපාංගයෙහි දත්ත මකනු ඇත."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"වැරදි උත්සාහයන් ඉතා වැඩි ගණනකි. මෙම පරිශීලකයා මකනු ඇත."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"වැරදි උත්සාහයන් ඉතා වැඩි ගණනකි. මෙම කාර්යාල පැතිකඩ සහ එහි දත්ත මකනු ඇත."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ඉවත ලන්න"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ඇඟිලි සලකුණු නිරූපකය"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • සෙමින් ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණ ඩොකය • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string> - <string name="user_add_user" msgid="4336657383006913022">"පරිශීලකයෙක් එක් කරන්න"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"නව පරිශීලකයා"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"අමුත්තාන් ඉවත් කරන්නද?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ඉවත් කරන්න"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්යද?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ඔව්, දිගටම කරගෙන යන්න"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"අලුත් පරිශීලකයෙක් එක් කරන්නද?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"ඔබ අලුත් පරිශීලකයෙක් එකතු කරන විට, එම පුද්ගලයා ඔහුගේ වැඩ කරන ඉඩ සකසා ගත යුතුය.\n\nසියළුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යාවත්කාලීන කළ හැක."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"පරිශීලක සීමාවට ළඟා විය"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">ඔබට පරිශීලකයින් <xliff:g id="COUNT">%d</xliff:g>ක් දක්වා එක් කළ හැකිය.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"භාවිත කිරීමට අගුලු හරින්න"</string> <string name="wallet_error_generic" msgid="257704570182963611">"ඔබගේ කාඩ්පත ලබා ගැනීමේ ගැටලුවක් විය, කරුණාකර පසුව නැවත උත්සාහ කරන්න"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"අගුලු තිර සැකසීම්"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR කේතය ස්කෑන් කරන්න"</string> <string name="status_bar_work" msgid="5238641949837091056">"කාර්යාල පැතිකඩ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ගුවන්යානා ප්රකාරය"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ඔබට ඔබේ ඊළඟ එලාමය <xliff:g id="WHEN">%1$s</xliff:g> නොඇසෙනු ඇත"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"තව බැලීමට ස්වයිප් කරන්න"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"නිර්දේශ පූරණය කරමින්"</string> <string name="controls_media_title" msgid="1746947284862928133">"මාධ්ය"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"මෙම මාධ්ය සැසිය සඟවන්නද?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"වත්මන් මාධ්ය සැසිය සැඟවිය නොහැකිය."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ඉවත ලන්න"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"සඟවන්න"</string> <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g>ගේ <xliff:g id="SONG_NAME">%1$s</xliff:g> ගීතය <xliff:g id="APP_LABEL">%3$s</xliff:g> වෙතින් ධාවනය වෙමින් පවතී"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"මෙහි ක්රීඩා කිරීමට <xliff:g id="DEVICENAME">%1$s</xliff:g> වෙත වඩා සමීප වන්න"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> හි වාදනය කරමින්"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"මෙම දුරකථනයෙහි වාදනය කරමින්"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"යම් දෙයක් වැරදිණි"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string> <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 5e29c9399777..17384203ca56 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ak pri ďalšom pokuse zadáte nesprávny vzor, váš pracovný profil a jeho dáta budú odstránené."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ak pri ďalšom pokuse zadáte nesprávny PIN, váš pracovný profil a jeho dáta budú odstránené."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ak pri ďalšom pokuse zadáte nesprávne heslo, váš pracovný profil a jeho dáta budú odstránené."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Príliš veľa chybných pokusov. Dáta tohto zariadenia budú odstránené."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Príliš veľa chybných pokusov. Tento používateľ bude odstránený."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Príliš veľa chybných pokusov. Tento pracovný profil a jeho dáta budú odstránené."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Zrušiť"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknite sa senzora odtlačkov prstov"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona odtlačku prsta"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa pomaly • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjací dok • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string> - <string name="user_add_user" msgid="4336657383006913022">"Pridať používateľa"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nový používateľ"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstrániť hosťa?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrániť"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Áno, pokračovať"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Pridať nového používateľa?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor.\n\nKtorýkoľvek používateľ môže aktualizovať aplikácie všetkých ostatných používateľov."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Dosiahnutý limit počtu používateľov"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="few">Môžete pridať maximálne <xliff:g id="COUNT">%d</xliff:g> používateľov.</item> @@ -796,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Potiahnutím zobrazíte ďalšie položky"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítavajú sa odporúčania"</string> <string name="controls_media_title" msgid="1746947284862928133">"Médiá"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Chcete skryť túto reláciu média?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Aktuálna relácia média sa nedá skryť."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Zavrieť"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skryť"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> od interpreta <xliff:g id="ARTIST_NAME">%2$s</xliff:g> sa prehráva z aplikácie <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -816,7 +808,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Ak chcete prehrávať v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>, priblížte sa k nemu"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Prehráva sa v zariadení <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Prehráva sa v tomto telefóne"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Vyskytol sa problém"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Niečo sa pokazilo. Skúste to znova."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládač nie je k dispozícii"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index cf9cb1c84212..ec68ce66afb8 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Če pri naslednjem poskusu vnesete napačen vzorec, bodo delovni profil in podatki v njem izbrisani."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Če pri naslednjem poskusu vnesete napačno kodo PIN, bodo delovni profil in podatki v njem izbrisani."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Če pri naslednjem poskusu vnesete napačno geslo, bodo delovni profil in podatki v njem izbrisani."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Preveč napačnih poskusov. Podatki v napravi bodo izbrisani."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Preveč napačnih poskusov. Uporabnik bo izbrisan."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Preveč napačnih poskusov. Delovni profil in podatki v njem bodo izbrisani."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Opusti"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotaknite se tipala prstnih odtisov"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona prstnih odtisov"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Počasno polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje na nosilcu • Polno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string> - <string name="user_add_user" msgid="4336657383006913022">"Dodajanje uporabnika"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Nov uporabnik"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite odstraniti gosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrani"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, nadaljuj"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Dodajanje novega uporabnika?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor.\n\nVsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Omejitev uporabnikov je dosežena"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Dodate lahko do <xliff:g id="COUNT">%d</xliff:g> uporabnika.</item> @@ -465,8 +456,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odklenite za uporabo"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Pri pridobivanju kartic je prišlo do težave. Poskusite znova pozneje."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavitve zaklepanja zaslona"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Optično branje kode QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil za Android Work"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način za letalo"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Naslednjega alarma ob <xliff:g id="WHEN">%1$s</xliff:g> ne boste slišali"</string> @@ -797,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Če si želite ogledati več, povlecite"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string> <string name="controls_media_title" msgid="1746947284862928133">"Predstavnost"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Želite skriti to sejo predstavnosti?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Trenutne seje predstavnosti ni mogoče skriti."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Opusti"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrij"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavitve"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Skladba <xliff:g id="SONG_NAME">%1$s</xliff:g> izvajalca <xliff:g id="ARTIST_NAME">%2$s</xliff:g> se predvaja iz aplikacije <xliff:g id="APP_LABEL">%3$s</xliff:g>."</string> @@ -817,7 +808,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Približajte napravi <xliff:g id="DEVICENAME">%1$s</xliff:g> za predvajanje v tej napravi"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Predvajanje v napravi <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Predvajanje v tem telefonu"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Prišlo je do težave"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Prišlo je do napake. Poskusite znova."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index fcf886818d42..c35b8d339641 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Nëse fut një motiv të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Nëse fut një kod PIN të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Nëse fut një fjalëkalim të pasaktë në tentativën tjetër, profili yt i punës dhe të dhënat e tij do të fshihen."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Shumë tentativa të pasakta. Të dhënat e kësaj pajisjeje do të fshihen."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Shumë tentativa të pasakta. Ky përdorues do të fshihet."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Shumë tentativa të pasakta. Ky profil pune dhe të dhënat e tij do të fshihen."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Hiq"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Prek sensorin e gjurmës së gishtit"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona e gjurmës së gishtit"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet ngadalë • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet në stacion • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string> - <string name="user_add_user" msgid="4336657383006913022">"Shto përdorues"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Përdorues i ri"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Të hiqet i ftuari?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hiq"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Mirë se erdhe, i ftuar!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Dëshiron ta vazhdosh sesionin tënd?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Fillo nga e para"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Po, vazhdo"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Të shtohet përdorues i ri?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet.\n\nÇdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"U arrit kufiri i përdoruesve"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Mund të shtosh deri në <xliff:g id="COUNT">%d</xliff:g> përdorues.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Shkyçe për ta përdorur"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Pati një problem me marrjen e kartave të tua. Provo përsëri më vonë"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cilësimet e ekranit të kyçjes"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skano kodin QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profili i punës"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modaliteti i aeroplanit"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nuk do ta dëgjosh alarmin e radhës në <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Rrëshqit shpejt për të shikuar më shumë"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Po ngarkon rekomandimet"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Të fshihet kjo seancë media?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Seanca aktuale e medias nuk mund të fshihet."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Hiq"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fshih"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> nga <xliff:g id="ARTIST_NAME">%2$s</xliff:g> po luhet nga <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Afrohu te <xliff:g id="DEVICENAME">%1$s</xliff:g> për ta luajtur këtu"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Po luhet në <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Po luhet në këtë telefon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Ndodhi një gabim"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 1025552b613d..ca5d2ec3490b 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ако унесете нетачан шаблон при следећем покушају, избрисаћемо пословни профил и његове податке."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ако унесете нетачан PIN при следећем покушају, избрисаћемо пословни профил и његове податке."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ако унесете нетачну лозинку при следећем покушају, избрисаћемо пословни профил и његове податке."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Превише нетачних покушаја. Избрисаћемо податке са овог уређаја."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Превише нетачних покушаја. Избрисаћемо овог корисника."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Превише нетачних покушаја. Избрисаћемо овај пословни профил и његове податке."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Одбаци"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Додирните сензор за отисак прста"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Икона отиска прста"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string> @@ -325,17 +321,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Споро се пуни • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Базна станица за пуњење • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string> - <string name="user_add_user" msgid="4336657383006913022">"Додај корисника"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Нови корисник"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Желите ли да уклоните госта?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Уклони"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, настави"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Додајете новог корисника?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Када додате новог корисника, та особа треба да подеси свој простор.\n\nСваки корисник може да ажурира апликације за све остале кориснике."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Достигнут максимални број корисника"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Можете да додате највише <xliff:g id="COUNT">%d</xliff:g> корисника.</item> @@ -790,9 +781,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Превуците да бисте видели још"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Учитавају се препоруке"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медији"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Желите ли да сакријете ову сесију медија?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Актуелна сесија медија не може да буде сакривена."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Одбаци"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сакриј"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> извођача <xliff:g id="ARTIST_NAME">%2$s</xliff:g> се пушта из апликације <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -810,7 +802,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Приближите се уређају <xliff:g id="DEVICENAME">%1$s</xliff:g> да бисте на њему пуштали"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Пушта се на уређају <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Пушта се на овом телефону"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Дошло је до грешке"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index ed89872724ba..9478a92932d6 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Jobbprofilen och dess data raderas om du ritar fel mönster vid nästa försök."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Jobbprofilen och dess data raderas om du anger fel pinkod vid nästa försök."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Din jobbprofil och dess data raderas om du anger fel lösenord vid nästa försök."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"För många felaktiga försök. Enhetens data raderas."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"För många felaktiga försök. Den här användaren raderas."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"För många felaktiga försök. Den här jobbprofilen och dess data raderas."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Stäng"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tryck på fingeravtryckssensorn"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikon för fingeravtryck"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas långsamt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Dockningsstation • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string> - <string name="user_add_user" msgid="4336657383006913022">"Lägg till användare"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Ny användare"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vill du ta bort gästen?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ta bort"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka som gäst!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ja, fortsätt"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Lägga till ny användare?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme.\n\nAlla användare kan uppdatera appar för samtliga användares räkning."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Användargränsen har nåtts"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Det går att lägga till upp till <xliff:g id="COUNT">%d</xliff:g> användare.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås upp för att använda"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Det gick inte att hämta dina kort. Försök igen senare."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Inställningar för låsskärm"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skanna QR-kod"</string> <string name="status_bar_work" msgid="5238641949837091056">"Jobbprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flygplansläge"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nästa alarm, kl. <xliff:g id="WHEN">%1$s</xliff:g>, kommer inte att höras"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Svep om du vill se mer"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Rekommendationer läses in"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Vill du dölja mediesessionen?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Den aktuella mediesessionen kan inte döljas."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Stäng"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Dölj"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> med <xliff:g id="ARTIST_NAME">%2$s</xliff:g> spelas upp från <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Flytta dig närmare <xliff:g id="DEVICENAME">%1$s</xliff:g> om du vill spela här"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Spelas upp på <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Spelas upp på denna telefon"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Något gick fel"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 2f184a1a7ee2..33b985a69210 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Ukiweka mchoro usio sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Ukiweka PIN isiyo sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Ukiweka nenosiri lisilo sahihi utakapojaribu tena, wasifu wako wa kazini utafutwa pamoja na data yake."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Umejaribu kufungua mara nyingi mno kwa njia isiyo sahihi. Data iliyo kwenye kifaa hiki itafutwa."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Umejaribu kufungua mara nyingi mno kwa njia isiyo sahihi. Maelezo ya mtumiaji huyu yatafutwa."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Umejaribu kufungua mara nyingi mno kwa njia isiyo sahihi. Wasifu huu wa kazini utafutwa pamoja na data yake."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ondoa"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Gusa kitambua alama ya kidole"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Aikoni ya alama ya kidole"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji polepole • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kituo cha Kuchaji • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string> - <string name="user_add_user" msgid="4336657383006913022">"Ongeza mtumiaji"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Mtumiaji mpya"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ungependa kumwondoa mgeni?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ondoa"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena mgeni!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza upya"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ndiyo, endelea"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Ungependa kuongeza mtumiaji?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Mtumiaji mpya utakayemwongeza atahitaji kuongeza akaunti yake.\n\nMtumiaji yoyote anaweza kusasisha programu kwa niaba ya wengine wote."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Umefikia kima cha juu cha watumiaji"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Unaruhusiwa kuongeza hadi watumiaji <xliff:g id="COUNT">%d</xliff:g>.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Fungua ili utumie"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Hitilafu imetokea wakati wa kuleta kadi zako, tafadhali jaribu tena baadaye"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mipangilio ya kufunga skrini"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Changanua msimbo wa QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Wasifu wa kazini"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Hali ya ndegeni"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Hutasikia kengele yako inayofuata ya saa <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Telezesha kidole ili uone zaidi"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string> <string name="controls_media_title" msgid="1746947284862928133">"Maudhui"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Ungependa kuficha kipindi hiki cha maudhui?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Kipindi cha sasa cha maudhui hakiwezi kufichwa."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ondoa"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ficha"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="SONG_NAME">%1$s</xliff:g> ulioimbwa na <xliff:g id="ARTIST_NAME">%2$s</xliff:g> unacheza katika <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sogeza karibu na <xliff:g id="DEVICENAME">%1$s</xliff:g> ili kucheza hapa"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Inacheza kwenye <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Inacheza kwenye simu hii"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Hitilafu fulani imetokea"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string> diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index 9f14d2f236b5..76780ffd2f80 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -38,6 +38,8 @@ <dimen name="status_bar_header_height_keyguard">42dp</dimen> + <dimen name="lockscreen_shade_max_over_scroll_amount">32dp</dimen> + <!-- Distance that the full shade transition takes in order to complete by tapping on a button like "expand". --> <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen> diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl b/packages/SystemUI/res/values-sw600dp-land/integers.xml index 8b9069f8fa48..919d6055667b 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl +++ b/packages/SystemUI/res/values-sw600dp-land/integers.xml @@ -1,5 +1,6 @@ -/** - * Copyright (c) 2011, The Android Open Source Project +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 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. @@ -12,8 +13,8 @@ * WITHOUT 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.net; - -parcelable NetworkStatsHistory; +*/ +--> +<resources> + <integer name="lockscreen_shade_over_scroll_release_duration">500</integer> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml index cff660d26cb1..0512d3c2c3a4 100644 --- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml @@ -26,4 +26,6 @@ <dimen name="status_bar_header_height_keyguard">56dp</dimen> <dimen name="qs_media_session_height_expanded">251dp</dimen> + + <dimen name="lockscreen_shade_max_over_scroll_amount">42dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index cd40c79f15bc..0d566301352b 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -88,7 +88,7 @@ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"ரெக்கார்டிங்கைத் தொடங்கவா?"</string> - <string name="screenrecord_description" msgid="1123231719680353736">"ரெக்கார்டு செய்யும்போது, உங்கள் திரையில் தோன்றக்கூடிய அல்லது சாதனத்தில் பிளே ஆகக்கூடிய ஏதேனும் அதிமுக்கியத் தகவலை Android சிஸ்டம் படமெடுக்க முடியும். கடவுச்சொற்கள், பேமெண்ட் தகவல், படங்கள், மெசேஜ்கள், ஆடியோ ஆகியவை இதில் அடங்கும்."</string> + <string name="screenrecord_description" msgid="1123231719680353736">"ரெக்கார்டு செய்யும்போது, உங்கள் திரையில் தோன்றக்கூடிய அல்லது சாதனத்தில் பிளே ஆகக்கூடிய பாதுகாக்கப்பட வேண்டிய தகவலை Android சிஸ்டம் படமெடுக்க முடியும். கடவுச்சொற்கள், பேமெண்ட் தகவல், படங்கள், மெசேஜ்கள், ஆடியோ ஆகியவை இதில் அடங்கும்."</string> <string name="screenrecord_audio_label" msgid="6183558856175159629">"ஆடியோவை ரெக்கார்டு செய்"</string> <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"சாதன ஆடியோ"</string> <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"இசை, அழைப்புகள், ரிங்டோன்கள் போன்ற உங்கள் சாதனத்திலிருந்து வரும் ஒலி"</string> @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"அடுத்த முறை தவறான பேட்டர்னை வரைந்தால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"அடுத்த முறை தவறான பின்னை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தப் பயனர் நீக்கப்படுவார்."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"பலமுறை தவறாக முயன்றதால், இந்தப் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"நிராகரி"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"கைரேகை சென்சாரைத் தொடவும்"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"கைரேகை ஐகான்"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • மெதுவாக சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுதும் சார்ஜாகும்"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • டாக் மூலம் சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுமையாகச் சார்ஜாகிவிடும்"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string> - <string name="user_add_user" msgid="4336657383006913022">"பயனரைச் சேர்"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"புதியவர்"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"கெஸ்ட்டை அகற்றவா?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"அகற்று"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"தொடரவும்"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"புதியவரைச் சேர்க்கவா?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"புதிய பயனரைச் சேர்க்கும்போது, அவர் தனக்கான இடத்தை அமைக்க வேண்டும்.\n\nஎந்தவொரு பயனரும், மற்ற எல்லா பயனர்களுக்காகவும் ஆப்ஸைப் புதுப்பிக்கலாம்."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"பயனர் வரம்பை அடைந்துவிட்டீர்கள்"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> பயனர்கள் வரை சேர்க்க முடியும்.</item> @@ -784,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"மேலும் பார்க்க ஸ்வைப் செய்யவும்"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string> <string name="controls_media_title" msgid="1746947284862928133">"மீடியா"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"இந்த மீடியா அமர்வை மறைக்க வேண்டுமா?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"தற்போதைய மீடியா அமர்வை மறைக்க முடியாது."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"மூடுக"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"மறை"</string> <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> இன் <xliff:g id="SONG_NAME">%1$s</xliff:g> பாடல் <xliff:g id="APP_LABEL">%3$s</xliff:g> ஆப்ஸில் பிளேயாகிறது"</string> @@ -804,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"இங்கு பிளே செய்ய உங்கள் சாதனத்தை <xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்திற்கு அருகில் நகர்த்துங்கள்"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> சாதனத்தில் பிளே ஆகிறது"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"இந்த மொபைலில் பிளே ஆகிறது"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"ஏதோ தவறாகிவிட்டது"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"ஏதோ தவறாகிவிட்டது. மீண்டும் முயலவும்."</string> <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string> <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 222da19a7254..96c1c13c8f96 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు ఆకృతిని ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు పిన్ను ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు పాస్వర్డ్ను ఎంటర్ చేస్తే, మీ కార్యాలయ ప్రొఫైల్, అలాగే దాని డేటా తొలగించబడతాయి."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ పరికరం యొక్క డేటా తొలగించబడుతుంది."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ యూజర్ తొలగించబడతారు."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు. ఈ కార్యాలయ ప్రొఫైల్ మరియు దీని డేటా తొలగించబడతాయి."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"తీసివేయి"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"వేలిముద్ర సెన్సార్ను తాకండి"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"వేలిముద్ర చిహ్నం"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • నెమ్మదిగా ఛార్జ్ అవుతోంది • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తి ఛార్జ్"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ఛార్జింగ్ డాక్ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string> - <string name="user_add_user" msgid="4336657383006913022">"యూజర్ను జోడించండి"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"కొత్త వినియోగదారు"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"గెస్ట్ను తీసివేయాలా?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"తీసివేయి"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"గెస్ట్కు తిరిగి స్వాగతం!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్ని కొనసాగించాలనుకుంటున్నారా?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"అవును, కొనసాగించు"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"కొత్త యూజర్ను జోడించాలా?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"ఒక కొత్త యూజర్ను మీరు జోడించినప్పుడు, ఆ వ్యక్తి తన స్పేస్ను సెటప్ చేసుకోవాలి.\n\nఏ యూజర్ అయినా మిగతా అందరు యూజర్ల కోసం యాప్లను అప్డేట్ చేయగలరు."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"వినియోగదారు పరిమితిని చేరుకున్నారు"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">మీరు <xliff:g id="COUNT">%d</xliff:g> వినియోగదారుల వరకు జోడించవచ్చు.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ఉపయోగించడానికి అన్లాక్ చేయండి"</string> <string name="wallet_error_generic" msgid="257704570182963611">"మీ కార్డ్లను పొందడంలో సమస్య ఉంది, దయచేసి తర్వాత మళ్లీ ట్రై చేయండి"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"లాక్ స్క్రీన్ సెట్టింగ్లు"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR కోడ్ను స్కాన్ చేయండి"</string> <string name="status_bar_work" msgid="5238641949837091056">"ఆఫీస్ ప్రొఫైల్"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ఎయిర్ప్లేన్ మోడ్"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"మీరు <xliff:g id="WHEN">%1$s</xliff:g> సెట్ చేసిన మీ తర్వాత అలారం మీకు వినిపించదు"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"మరిన్నింటిని చూడటం కోసం స్వైప్ చేయండి"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string> <string name="controls_media_title" msgid="1746947284862928133">"మీడియా"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ఈ మీడియా సెషన్ను దాచాలా?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"ప్రస్తుత మీడియా సెషన్ను దాచడం సాధ్యం కాదు."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"విస్మరించు"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"దాచు"</string> <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్లు"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g> <xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి ప్లే అవుతోంది"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ఇక్కడ ప్లే చేయడానికి <xliff:g id="DEVICENAME">%1$s</xliff:g>కి దగ్గరగా వెళ్లండి"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g>లో ప్లే అవుతోంది"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"ఈ ఫోన్లో ప్లే అవుతోంది"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"ఏదో తప్పు జరిగింది"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్యాక్టివ్, యాప్ చెక్ చేయండి"</string> <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 120d87077454..a6ae2bd3dbf9 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"หากคุณป้อนรูปแบบไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"หากคุณป้อน PIN ไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"หากคุณป้อนรหัสผ่านไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบโปรไฟล์งานและข้อมูลในโปรไฟล์"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบข้อมูลในอุปกรณ์เครื่องนี้"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบผู้ใช้รายนี้"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"ใช้ความพยายามหลายครั้งเกินไป ระบบจะลบโปรไฟล์งานนี้และข้อมูลในโปรไฟล์"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"ปิด"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"แตะเซ็นเซอร์ลายนิ้วมือ"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"ไอคอนลายนิ้วมือ"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จอย่างช้าๆ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จบนแท่นชาร์จ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string> - <string name="user_add_user" msgid="4336657383006913022">"เพิ่มผู้ใช้"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"ผู้ใช้ใหม่"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ต้องการนำผู้ใช้ชั่วคราวออกไหม"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"นำออก"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับผู้เข้าร่วมกลับมาอีกครั้ง"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ใช่ ดำเนินการต่อ"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"ต้องการเพิ่มผู้ใช้ใหม่ใช่ไหม"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง\n\nผู้ใช้ทุกคนสามารถอัปเดตแอปสำหรับผู้ใช้รายอื่นทุกคนได้"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"ถึงขีดจำกัดผู้ใช้แล้ว"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">คุณเพิ่มผู้ใช้ได้สูงสุด <xliff:g id="COUNT">%d</xliff:g> คน</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ปลดล็อกเพื่อใช้"</string> <string name="wallet_error_generic" msgid="257704570182963611">"เกิดปัญหาในการดึงข้อมูลบัตรของคุณ โปรดลองอีกครั้งในภายหลัง"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"การตั้งค่าหน้าจอล็อก"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"สแกนคิวอาร์โค้ด"</string> <string name="status_bar_work" msgid="5238641949837091056">"โปรไฟล์งาน"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"โหมดบนเครื่องบิน"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"คุณจะไม่ได้ยินเสียงปลุกครั้งถัดไปในเวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"เลื่อนเพื่อดูเพิ่มเติม"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"กำลังโหลดคำแนะนำ"</string> <string name="controls_media_title" msgid="1746947284862928133">"สื่อ"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"ซ่อนเซสชันสื่อนี้ไหม"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"ซ่อนเซสชันสื่อในปัจจุบันไม่ได้"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ปิด"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ซ่อน"</string> <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"กำลังเปิดเพลง <xliff:g id="SONG_NAME">%1$s</xliff:g> ของ <xliff:g id="ARTIST_NAME">%2$s</xliff:g> จาก <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"ขยับไปใกล้ <xliff:g id="DEVICENAME">%1$s</xliff:g> มากขึ้นเพื่อเล่นที่นี่"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"กำลังเล่นใน <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"กำลังเล่นในโทรศัพท์เครื่องนี้"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"เกิดข้อผิดพลาด"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"เกิดข้อผิดพลาด โปรดลองอีกครั้ง"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string> <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 4d5655c191d6..d6715a3f1954 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Kung maling pattern ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Kung maling PIN ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Kung maling password ang mailalagay mo sa susunod na pagsubok, made-delete ang iyong profile sa trabaho at ang data nito."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Masyadong maraming maling pagsubok. Made-delete ang data ng device na ito."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Masyadong maraming maling pagsubok. Made-delete ang user na ito."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Masyadong maraming maling pagsubok. Made-delete ang profile sa trabaho na ito at ang data nito."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"I-dismiss"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pindutin ang fingerprint sensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Icon ng fingerprint"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mabagal na nagcha-charge • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> na lang para mapuno"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging Dock • Mapupuno sa loob ng <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string> - <string name="user_add_user" msgid="4336657383006913022">"Magdagdag ng user"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Bagong user"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alisin ang bisita?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alisin"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome ulit, bisita!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Oo, magpatuloy"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Magdagdag ng bagong user?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo.\n\nAng sinumang user ay maaaring mag-update ng mga app para sa lahat ng iba pang user."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Naabot na ang limitasyon sa user"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Maaari kang magdagdag ng hanggang <xliff:g id="COUNT">%d</xliff:g> user.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"I-unlock para magamit"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Nagkaproblema sa pagkuha ng iyong mga card, pakisubukan ulit sa ibang pagkakataon"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mga setting ng lock screen"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"I-scan ang QR code"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profile sa trabaho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Hindi mo maririnig ang iyong susunod na alarm ng <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Mag-swipe para tumingin ng higit pa"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nilo-load ang rekomendasyon"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Itago ang session ng media na ito?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Hindi maitatago ang kasalukuyang session ng media."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"I-dismiss"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Itago"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Nagpe-play ang <xliff:g id="SONG_NAME">%1$s</xliff:g> ni/ng <xliff:g id="ARTIST_NAME">%2$s</xliff:g> mula sa <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Lumapit sa <xliff:g id="DEVICENAME">%1$s</xliff:g> para mag-play rito"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Nagpe-play sa <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Nagpe-play sa teleponong ito"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Nagkaproblema"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 170d582f8583..6cc170333207 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Bir sonraki denemenizde yanlış desen girerseniz iş profiliniz ve verileri silinir."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Bir sonraki denemenizde yanlış PIN girerseniz iş profiliniz ve verileri silinir."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Bir sonraki denemenizde yanlış şifre girerseniz iş profiliniz ve verileri silinir."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Çok fazla sayıda hatalı deneme yapıldı. Bu cihazın verileri silinecek."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Çok fazla sayıda hatalı deneme yapıldı. Bu kullanıcı silinecek."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Çok fazla sayıda hatalı denemede yapıldı. İş profiliniz ve verileri silinecek."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Kapat"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Parmak izi sensörüne dokunun"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Parmak izi simgesi"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yavaş şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Yuvada Şarj Oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string> - <string name="user_add_user" msgid="4336657383006913022">"Kullanıcı ekle"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Yeni kullanıcı"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Misafir oturumu kaldırılsın mı?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kaldır"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Misafir kullanıcı, tekrar hoşgeldiniz"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Evet, devam et"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Yeni kullanıcı eklensin mi?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Yeni bir kullanıcı eklediğinizde, bu kişinin kendi alanını ayarlaması gerekir.\n\nHerhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Kullanıcı sınırına ulaşıldı"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">En fazla <xliff:g id="COUNT">%d</xliff:g> kullanıcı ekleyebilirsiniz.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Kullanmak için kilidi aç"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Kartlarınız alınırken bir sorun oluştu. Lütfen daha sonra tekrar deneyin"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Kilit ekranı ayarları"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodunu tara"</string> <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Uçak modu"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> olarak ayarlanmış bir sonraki alarmınızı duymayacaksınız"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Diğer öğeleri görmek için hızlıca kaydırın"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Öneriler yükleniyor"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medya"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Bu medya oturumu gizlensin mi?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Geçerli medya oturumu gizlenemez."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Kapat"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizle"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> uygulamasından <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, <xliff:g id="SONG_NAME">%1$s</xliff:g> şarkısı çalıyor"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Burada oynatmak için <xliff:g id="DEVICENAME">%1$s</xliff:g> cihazına yaklaşın"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> cihazında oynatılıyor"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda oynatılıyor"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Hata oluştu"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 87ea462dfb25..1bc89c87ea06 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Якщо наступного разу ви введете неправильний ключ, ваш робочий профіль і його дані буде видалено."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Якщо наступного разу ви введете неправильний PIN-код, ваш робочий профіль і його дані буде видалено."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Якщо наступного разу ви введете неправильний пароль, ваш робочий профіль і його дані буде видалено."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Забагато невдалих спроб. Дані на цьому пристрої буде видалено."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Забагато невдалих спроб. Цього користувача буде видалено."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Забагато невдалих спроб. Цей робочий профіль і його дані буде видалено."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Закрити"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Торкніться сканера відбитків пальців"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Значок відбитка пальця"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string> @@ -327,17 +323,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Повільне заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Док-станція для заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string> - <string name="user_add_user" msgid="4336657383006913022">"Додати користувача"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Новий користувач"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Видалити гостя?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Вийти"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"З поверненням!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продовжити сеанс?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почати знову"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Так, продовжити"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Додати нового користувача?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Користувач має налаштувати свій профіль після створення.\n\nБудь-який користувач пристрою може оновлювати додатки для решти користувачів."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Ви досягли ліміту користувачів"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Можна додати до <xliff:g id="COUNT">%d</xliff:g> користувача.</item> @@ -465,8 +456,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Розблокувати, щоб використовувати"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Не вдалось отримати ваші картки. Повторіть спробу пізніше."</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Параметри блокування екрана"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Сканувати QR-код"</string> <string name="status_bar_work" msgid="5238641949837091056">"Робочий профіль"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Режим польоту"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Наступний сигнал о <xliff:g id="WHEN">%1$s</xliff:g> не пролунає"</string> @@ -797,9 +787,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Гортайте, щоб переглянути інші"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медіа"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Приховати цей медіасеанс?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Поточний медіасеанс не можна приховати."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Закрити"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Приховати"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налаштування"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Пісня \"<xliff:g id="SONG_NAME">%1$s</xliff:g>\", яку виконує <xliff:g id="ARTIST_NAME">%2$s</xliff:g>, грає в додатку <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -817,7 +808,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Наблизьтеся до пристрою <xliff:g id="DEVICENAME">%1$s</xliff:g>, щоб відтворити медіафайли на ньому"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Відтворюється на пристрої <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Відтворюється на цьому телефоні"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Сталася помилка"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index cb1cbddfa0a9..5c1d4d655e60 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"اگر آپ نے اگلی کوشش میں غلط پیٹرن درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"اگر آپ نے اگلی کوشش میں غلط PIN درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"اگر آپ نے اگلی کوشش میں غلط پاس ورڈ درج کیا تو آپ کی دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"بہت زیادہ غلط کوششیں۔ اس آلے کا ڈیٹا حذف کر دیا جائے گا۔"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"بہت زیادہ غلط کوششیں۔ اس صارف کو حذف کر دیا جائے گا۔"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"بہت زیادہ غلط کوششیں۔ یہ دفتری پروفائل اور اس کا ڈیٹا حذف کر دیا جائے گا۔"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"برخاست کریں"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"فنگر پرنٹ سینسر پر ٹچ کریں"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"فنگر پرنٹ آئیکن"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • آہستہ چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ڈاک چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string> - <string name="user_add_user" msgid="4336657383006913022">"صارف کو شامل کریں"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"نیا صارف"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مہمان کو ہٹائیں؟"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ہٹائیں"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"ہاں، جاری رکھیں"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"نیا صارف شامل کریں؟"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"جب آپ ایک نیا صارف شامل کرتے ہیں تو اس شخص کو اپنی جگہ کو ترتیب دینے کی ضرورت ہوتی ہے۔\n\nکوئی بھی صارف دیگر سبھی صارفین کیلئے ایپس کو اپ ڈیٹ کر سکتا ہے۔"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"صارف کی حد مکمل ہو گئی"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">صرف <xliff:g id="COUNT">%d</xliff:g> صارفین بنائے جا سکتے ہیں۔</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"استعمال کرنے کے لیے غیر مقفل کریں"</string> <string name="wallet_error_generic" msgid="257704570182963611">"آپ کے کارڈز حاصل کرنے میں ایک مسئلہ درپیش تھا، براہ کرم بعد میں دوبارہ کوشش کریں"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"مقفل اسکرین کی ترتیبات"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR کوڈ اسکین کریں"</string> <string name="status_bar_work" msgid="5238641949837091056">"دفتری پروفائل"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ہوائی جہاز وضع"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"آپ کو <xliff:g id="WHEN">%1$s</xliff:g> بجے اپنا اگلا الارم سنائی نہیں دے گا"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"مزید دیکھنے کیلئے سوائپ کریں"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string> <string name="controls_media_title" msgid="1746947284862928133">"میڈیا"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"اس میڈیا سیشن کو چھپائیں؟"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"میڈیا کے موجودہ سیشن کو چھپایا نہیں جا سکتا۔"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"برخاست کریں"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"چھپائیں"</string> <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> سے <xliff:g id="ARTIST_NAME">%2$s</xliff:g> کا <xliff:g id="SONG_NAME">%1$s</xliff:g> چل رہا ہے"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"یہاں چلانے کے ليے <xliff:g id="DEVICENAME">%1$s</xliff:g> کے قریب جائیں"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> پر چل رہا ہے"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"اس فون پر چل رہا ہے"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"کچھ غلط ہو گیا"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string> <string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 1128b297a56f..95111c717cac 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Agar grafik kalitni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Agar PIN kodni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Agar parolni xato kiritsangiz, ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu qurilmadagi maʼlumotlar oʻchirib tashlanadi."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu foydalanuvchi oʻchirib tashlanadi."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Juda koʻp marta muvaffaqiyatsiz urindingiz. Bu ish profili va undagi maʼlumotlar oʻchirib tashlanadi."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Yopish"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmoq izi skaneriga tegining"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Barmoq izi belgisi"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sekin quvvat olmoqda • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Dok-stansiya • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string> - <string name="user_add_user" msgid="4336657383006913022">"Foydalanuvchi"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Yangi foydalanuvchi"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Mehmon olib tashlansinmi?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Olib tashlash"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xush kelibsiz, mehmon!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Seansni davom ettirmoqchimisiz?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Boshidan boshlansin"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Ha, davom ettirilsin"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Foydalanuvchi qo‘shilsinmi?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Yangi profil qo‘shilgach, uni sozlash lozim.\n\nQurilmaning istalgan foydalanuvchisi ilovalarni barcha hisoblar uchun yangilashi mumkin."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Limitga yetib keldi"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> tagacha foydalanuvchi qo‘shish mumkin.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Foydalanish uchun qulfdan chiqarish"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Bildirgilarni yuklashda xatolik yuz berdi, keyinroq qaytadan urining"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Qulflangan ekran sozlamalari"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"QR kodni skanerlash"</string> <string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Keyingi signal (<xliff:g id="WHEN">%1$s</xliff:g>) chalinmaydi"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Batafsil axborot olish uchun suring"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Bu media seansi berkitilsinmi?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Joriy media seansi berkitilmadi."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Yopish"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Berkitish"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"<xliff:g id="APP_LABEL">%3$s</xliff:g> ilovasida ijro etilmoqda: <xliff:g id="SONG_NAME">%1$s</xliff:g> – <xliff:g id="ARTIST_NAME">%2$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Bu yerda ijro qilish uchun <xliff:g id="DEVICENAME">%1$s</xliff:g>qurilmasiga yaqinlashtiring"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"<xliff:g id="DEVICENAME">%1$s</xliff:g> qurilmasida ijro qilinmoqda"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Bu telefonda ijro etilmoqda"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Xatolik yuz berdi"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Xatolik yuz berdi. Qayta urining."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 068127b17e98..499495fb2569 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Nếu bạn nhập hình mở khóa không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Nếu bạn nhập mã PIN không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Nếu bạn nhập mật khẩu không chính xác vào lần thử tiếp theo, thì hồ sơ công việc của bạn và dữ liệu của hồ sơ công việc sẽ bị xóa."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Dữ liệu trên thiết bị này sẽ bị xóa do có quá nhiều lần nhập sai khóa thiết bị."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Người dùng này sẽ bị xóa do có quá nhiều lần nhập sai khóa người dùng."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Hồ sơ công việc này và dữ liệu của hồ sơ công việc sẽ bị xóa do có quá nhiều lần nhập sai khóa công việc."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Đóng"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Chạm vào cảm biến vân tay"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Biểu tượng vân tay"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc chậm • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đế sạc • Sạc đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string> - <string name="user_add_user" msgid="4336657383006913022">"Thêm người dùng"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Người dùng mới"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Xóa phiên khách?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Xóa"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Có, tiếp tục"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Thêm người dùng mới?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Khi bạn thêm người dùng mới, họ cần thiết lập không gian của mình.\n\nMọi người dùng đều có thể cập nhật ứng dụng cho tất cả người dùng khác."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Đã đạt đến giới hạn người dùng"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">Bạn có thể thêm tối đa <xliff:g id="COUNT">%d</xliff:g> người dùng.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Mở khóa để sử dụng"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Đã xảy ra sự cố khi tải thẻ của bạn. Vui lòng thử lại sau"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Cài đặt màn hình khóa"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Quét mã QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ máy bay"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy báo thức tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Vuốt để xem thêm"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Đang tải các đề xuất"</string> <string name="controls_media_title" msgid="1746947284862928133">"Nội dung nghe nhìn"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Ẩn phiên phát nội dung nghe nhìn này?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Không thể ẩn phiên phát nội dung nghe nhìn hiện tại."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Đóng"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ẩn"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"Đang phát <xliff:g id="SONG_NAME">%1$s</xliff:g> của <xliff:g id="ARTIST_NAME">%2$s</xliff:g> trên <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Di chuyển đến gần <xliff:g id="DEVICENAME">%1$s</xliff:g> hơn để phát tại đây"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Đang phát trên <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Đang phát trên điện thoại này"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Đã xảy ra lỗi"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index b5671e6df9e7..3c459f689546 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果您下次绘制的解锁图案仍然有误,您的工作资料及其相关数据将会被删除。"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果您下次输入的 PIN 码仍然有误,您的工作资料及其相关数据将会被删除。"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果您下次输入的密码仍然有误,您的工作资料及其相关数据将会被删除。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"错误次数过多。系统将删除此设备上的数据。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"错误次数过多。系统将删除此用户。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"错误次数过多。系统将删除此工作资料和相关数据。"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"关闭"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"请触摸指纹传感器"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指纹图标"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在慢速充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在基座上充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string> - <string name="user_add_user" msgid="4336657383006913022">"添加用户"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"新用户"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"要移除访客吗?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是,继续"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"要添加新用户吗?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"当您添加新用户时,该用户必须设置自己的空间。\n\n任何用户均可为其他所有用户更新应用。"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"已达到用户数上限"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">您最多可以添加 <xliff:g id="COUNT">%d</xliff:g> 位用户。</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解锁设备即可使用"</string> <string name="wallet_error_generic" msgid="257704570182963611">"获取您的卡片时出现问题,请稍后重试"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"锁定屏幕设置"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"扫描二维码"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作资料"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飞行模式"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑动可查看更多结构"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在加载推荐内容"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒体"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"要隐藏此媒体会话吗?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"无法隐藏当前的媒体会话。"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"关闭"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隐藏"</string> <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"设置"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在通过<xliff:g id="APP_LABEL">%3$s</xliff:g>播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"若要在此设备上播放,请靠近“<xliff:g id="DEVICENAME">%1$s</xliff:g>”"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在“<xliff:g id="DEVICENAME">%1$s</xliff:g>”上播放"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在此手机上播放"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"出了点问题"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string> <string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 718d5e1f7e5e..ee9757560b7f 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果您下次畫出錯誤的上鎖圖案,系統將會刪除工作設定檔和相關資料。"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果您下次輸入錯誤的 PIN,系統將會刪除工作設定檔和相關資料。"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果您下次輸入錯誤的密碼,系統將會刪除工作設定檔和相關資料。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"錯誤次數太多,系統將會刪除此裝置上的資料。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"錯誤次數太多,系統將會刪除此使用者。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"錯誤次數太多,系統將會刪除此工作設定檔和相關資料。"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"關閉"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋圖示"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 慢速充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在插座上充電 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> - <string name="user_add_user" msgid="4336657383006913022">"加入使用者"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是的,請繼續"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"新增使用者?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"新增的使用者需要自行設定個人空間。\n\n任何使用者均可為所有其他使用者更新應用程式。"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"已達到使用者上限"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">您可以加入多達 <xliff:g id="COUNT">%d</xliff:g> 個使用者。</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string> <string name="wallet_error_generic" msgid="257704570182963611">"擷取資訊卡時發生問題,請稍後再試。"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"上鎖畫面設定"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"掃瞄 QR 碼"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作設定檔"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飛行模式"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"您不會<xliff:g id="WHEN">%1$s</xliff:g>聽到鬧鐘"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動以查看更多"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"要隱藏此媒體工作階段嗎?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"無法隱藏目前的媒體工作階段。"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"關閉"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string> <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"正在透過 <xliff:g id="APP_LABEL">%3$s</xliff:g> 播放 <xliff:g id="ARTIST_NAME">%2$s</xliff:g> 的《<xliff:g id="SONG_NAME">%1$s</xliff:g>》"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在此裝置上播放,請靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在此手機上播放"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"發生錯誤"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string> <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index dcb74b30a6cd..5257afe88b8e 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"如果下次輸入的解鎖圖案仍不正確,系統將刪除你的工作資料夾和相關資料。"</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"如果下次輸入的 PIN 碼仍不正確,系統將刪除你的工作資料夾和相關資料。"</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"如果下次輸入的密碼仍不正確,系統將刪除你的工作資料夾和相關資料。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"錯誤次數過多,系統將刪除這部裝置中的資料。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"錯誤次數過多,系統將刪除這位使用者。"</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"錯誤次數過多,系統將刪除這個工作資料夾和相關資料。"</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"關閉"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"指紋圖示"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 慢速充電中 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在座架上充電 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> - <string name="user_add_user" msgid="4336657383006913022">"新增使用者"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"是,繼續"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"要新增使用者嗎?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"新增的使用者需要自行設定個人空間。\n\n任何使用者皆可為其他所有使用者更新應用程式。"</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"已達使用者數量上限"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="other">最多可新增 <xliff:g id="COUNT">%d</xliff:g> 位使用者。</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"解鎖即可使用"</string> <string name="wallet_error_generic" msgid="257704570182963611">"擷取卡片時發生問題,請稍後再試"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"螢幕鎖定設定"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"掃描 QR 圖碼"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作資料夾"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飛航模式"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"你不會聽到下一個<xliff:g id="WHEN">%1$s</xliff:g> 的鬧鐘"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動即可查看其他結構"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"要隱藏這個媒體工作階段嗎?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"無法隱藏目前的媒體工作階段。"</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"關閉"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string> <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"系統正透過「<xliff:g id="APP_LABEL">%3$s</xliff:g>」播放<xliff:g id="ARTIST_NAME">%2$s</xliff:g>的〈<xliff:g id="SONG_NAME">%1$s</xliff:g>〉"</string> @@ -805,7 +796,8 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"如要在這部裝置上播放,請移到更靠近「<xliff:g id="DEVICENAME">%1$s</xliff:g>」的位置"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"正在「<xliff:g id="DEVICENAME">%1$s</xliff:g>」上播放"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"正在這支手機上播放"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"發生錯誤"</string> + <!-- no translation found for media_transfer_failed (7955354964610603723) --> + <skip /> <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string> <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index f26ef0efa126..1a0f74bc00e9 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -151,10 +151,6 @@ <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Uma ufaka iphethini engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string> <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Uma ufaka iphinikhodi engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string> <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Uma ufake iphasiwedi engalungile kumzamo olandelayo, iphrofayela yakho yomsebenzi nedatha yayo izosuswa."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Imizamo eminingi kakhulu engalungile. Le datha yedivayisi izosuswa."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Imizamo eminingi kakhulu engalungile. Lo msebenzisi uzosuswa."</string> - <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Imizamo eminingi kakhulu engalungile. Le phrofayela yomsebenzi nedatha yayo kuzosuswa."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Cashisa"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Thinta inzwa yesigxivizo zeminwe"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Isithonjana sezigxivizo zeminwe"</string> <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string> @@ -323,17 +319,12 @@ <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ishaja kancane • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="keyguard_indication_charging_time_dock" msgid="6150404291427377863">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ukushaja Idokhi • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string> - <string name="user_add_user" msgid="4336657383006913022">"Engeza umsebenzisi"</string> - <string name="user_new_user_name" msgid="2019166282704195789">"Umsebenzisi omusha"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Susa isivakashi?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Susa"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string> <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Yebo, qhubeka"</string> - <string name="user_add_user_title" msgid="4172327541504825032">"Engeza umsebenzisi omusha?"</string> - <string name="user_add_user_message_short" msgid="2599370307878014791">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha isikhala sakhe.\n\nNoma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza kubo bonke abasebenzisi."</string> <string name="user_limit_reached_title" msgid="2429229448830346057">"Kufinyelelwe kumkhawulo womsebenzisi"</string> <plurals name="user_limit_reached_message" formatted="false" msgid="2573535787802908398"> <item quantity="one">Ungangeza kufikela kubasebenzisi abangu-<xliff:g id="COUNT">%d</xliff:g>.</item> @@ -459,8 +450,7 @@ <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Vula ukuze usebenzise"</string> <string name="wallet_error_generic" msgid="257704570182963611">"Kube khona inkinga yokuthola amakhadi akho, sicela uzame futhi ngemuva kwesikhathi"</string> <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Amasethingi okukhiya isikrini"</string> - <!-- no translation found for qr_code_scanner_title (5290201053875420785) --> - <skip /> + <string name="qr_code_scanner_title" msgid="5290201053875420785">"Skena ikhodi ye-QR"</string> <string name="status_bar_work" msgid="5238641949837091056">"Iphrofayela yomsebenzi"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Imodi yendiza"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ngeke uzwe i-alamu yakho elandelayo ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -785,9 +775,10 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swayipha ukuze ubone okuningi"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ilayisha izincomo"</string> <string name="controls_media_title" msgid="1746947284862928133">"Imidiya"</string> - <string name="controls_media_close_session" msgid="1193000643003066508">"Fihla le seshini yemidiya?"</string> + <!-- no translation found for controls_media_close_session (4780485355795635052) --> + <skip /> <string name="controls_media_active_session" msgid="3146882316024153337">"Iseshini yamanje yemidiya ayikwazi ukufihlwa."</string> - <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Cashisa"</string> + <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fihla"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string> <string name="controls_media_playing_item_description" msgid="4531853311504359098">"I-<xliff:g id="SONG_NAME">%1$s</xliff:g> ka-<xliff:g id="ARTIST_NAME">%2$s</xliff:g> idlala kusuka ku-<xliff:g id="APP_LABEL">%3$s</xliff:g>"</string> @@ -805,7 +796,7 @@ <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Sondela eduze ne-<xliff:g id="DEVICENAME">%1$s</xliff:g> ukuze udlale lapha"</string> <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Idlala ku-<xliff:g id="DEVICENAME">%1$s</xliff:g>"</string> <string name="media_transfer_playing_this_device" msgid="1856890686844499172">"Okudlala kule foni"</string> - <string name="media_transfer_failed" msgid="2640354446629980227">"Kukhona okungahambanga kahle"</string> + <string name="media_transfer_failed" msgid="7955354964610603723">"Kukhona okungahambanga kahle. Zama futhi."</string> <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string> <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string> <string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a309cc4ff1f5..f39b5efdca24 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1174,9 +1174,8 @@ the shade --> <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen> - <!-- Maximum overshoot for the topPadding of notifications when transitioning to the full - shade --> - <dimen name="lockscreen_shade_notification_movement">24dp</dimen> + <!-- Maximum over scroll amount for the shade when transition to the full shade. --> + <dimen name="lockscreen_shade_max_over_scroll_amount">24dp</dimen> <!-- Maximum overshoot for the pulse expansion --> <dimen name="pulse_expansion_max_top_overshoot">32dp</dimen> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 096b9a0c4790..926734c2749f 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -167,11 +167,5 @@ <item type="id" name="action_move_bottom_right"/> <item type="id" name="action_move_to_edge_and_hide"/> <item type="id" name="action_move_out_edge_and_show"/> - - <!-- rounded corner view id --> - <item type="id" name="rounded_corner_top_left"/> - <item type="id" name="rounded_corner_top_right"/> - <item type="id" name="rounded_corner_bottom_left"/> - <item type="id" name="rounded_corner_bottom_right"/> </resources> diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index f0f7a196d694..3164ed1e6751 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -25,4 +25,7 @@ See com.android.systemui.volume.VolumeDialogImpl. Value 21 corresponds to RIGHT|CENTER_VERTICAL. --> <integer name="volume_dialog_gravity">21</integer> + + <!-- The time it takes for the over scroll release animation to complete, in milli seconds. --> + <integer name="lockscreen_shade_over_scroll_release_duration">0</integer> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index a61eda8f0e09..477658745205 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -616,7 +616,6 @@ parent="@android:style/Widget.Material.Button.Borderless.Small"> <item name="android:background">@drawable/qs_media_light_source</item> <item name="android:tint">?android:attr/textColorPrimary</item> - <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item> <item name="android:paddingTop">12dp</item> <item name="android:paddingStart">12dp</item> <item name="android:paddingEnd">12dp</item> @@ -629,6 +628,10 @@ <item name="android:backgroundTint">@color/media_player_solid_button_bg</item> </style> + <style name="MediaPlayer.SessionAction.Secondary" parent="MediaPlayer.SessionAction"> + <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item> + </style> + <style name="MediaPlayer.OutlineButton"> <item name="android:background">@drawable/qs_media_outline_button</item> <item name="android:textColor">?android:attr/textColorPrimary</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java index b61827a0212c..51001a7a4c8e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -331,13 +331,12 @@ public class RemoteTransitionCompat implements Parcelable { } if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint); final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - final WindowContainerTransaction wct; + final WindowContainerTransaction wct = new WindowContainerTransaction(); if (!toHome && mPausingTasks != null && mOpeningLeashes == null) { // The gesture went back to opening the app rather than continuing with // recents, so end the transition by moving the app back to the top (and also // re-showing it's task). - wct = new WindowContainerTransaction(); for (int i = mPausingTasks.size() - 1; i >= 0; --i) { // reverse order so that index 0 ends up on top wct.reorder(mPausingTasks.get(i), true /* onTop */); @@ -347,8 +346,14 @@ public class RemoteTransitionCompat implements Parcelable { wct.restoreTransientOrder(mRecentsTask); } } else { - wct = null; - if (mPipTask != null && mPipTransaction != null) { + if (!sendUserLeaveHint) { + for (int i = 0; i < mPausingTasks.size(); ++i) { + // This means recents is not *actually* finishing, so of course we gotta + // do special stuff in WMCore to accommodate. + wct.setDoNotPip(mPausingTasks.get(i)); + } + } + if (mPipTask != null && mPipTransaction != null && sendUserLeaveHint) { t.show(mInfo.getChange(mPipTask).getLeash()); PictureInPictureSurfaceTransaction.apply(mPipTransaction, mInfo.getChange(mPipTask).getLeash(), t); @@ -363,7 +368,7 @@ public class RemoteTransitionCompat implements Parcelable { t.remove(mLeashMap.valueAt(i)); } try { - mFinishCB.onTransitionFinished(wct, t); + mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t); } catch (RemoteException e) { Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e); t.apply(); diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt index 15593ea5f0e4..9e5aeb84b624 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldSharedComponent.kt @@ -16,6 +16,7 @@ package com.android.systemui.unfold +import android.app.ActivityManager import android.content.ContentResolver import android.content.Context import android.hardware.SensorManager @@ -51,6 +52,7 @@ internal interface UnfoldSharedComponent { @BindsInstance config: UnfoldTransitionConfig, @BindsInstance screenStatusProvider: ScreenStatusProvider, @BindsInstance deviceStateManager: DeviceStateManager, + @BindsInstance activityManager: ActivityManager, @BindsInstance sensorManager: SensorManager, @BindsInstance @Main handler: Handler, @BindsInstance @Main executor: Executor, diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt index 8e4ff9bc9133..cc56007c431a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt @@ -17,6 +17,7 @@ package com.android.systemui.unfold +import android.app.ActivityManager import android.content.Context import android.hardware.SensorManager import android.hardware.devicestate.DeviceStateManager @@ -39,6 +40,7 @@ fun createUnfoldTransitionProgressProvider( config: UnfoldTransitionConfig, screenStatusProvider: ScreenStatusProvider, deviceStateManager: DeviceStateManager, + activityManager: ActivityManager, sensorManager: SensorManager, mainHandler: Handler, mainExecutor: Executor, @@ -51,6 +53,7 @@ fun createUnfoldTransitionProgressProvider( config, screenStatusProvider, deviceStateManager, + activityManager, sensorManager, mainHandler, mainExecutor, diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt index 5266f096e12c..3daae75aaed7 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt @@ -33,7 +33,7 @@ import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener /** Maps fold updates to unfold transition progress using DynamicAnimation. */ -internal class PhysicsBasedUnfoldTransitionProgressProvider( +class PhysicsBasedUnfoldTransitionProgressProvider( private val foldStateProvider: FoldStateProvider ) : UnfoldTransitionProgressProvider, FoldUpdatesListener, DynamicAnimation.OnAnimationEndListener { @@ -97,7 +97,17 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider( FOLD_UPDATE_START_CLOSING -> { // The transition might be already running as the device might start closing several // times before reaching an end state. - if (!isTransitionRunning) { + if (isTransitionRunning) { + // If we are cancelling the animation, reset that so we can resume it normally. + // The animation could be 'cancelled' when the user stops folding/unfolding + // for some period of time or fully unfolds the device. In this case, + // it is forced to run to the end ignoring all further hinge angle events. + // By resetting this flag we allow reacting to hinge angle events again, so + // the transition continues running. + if (isAnimatedCancelRunning) { + isAnimatedCancelRunning = false + } + } else { startTransition(startValue = 1f) } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index 24ecf8781a18..eb1181d98bec 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -16,6 +16,8 @@ package com.android.systemui.unfold.updates import android.annotation.FloatRange +import android.app.ActivityManager +import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.content.Context import android.hardware.devicestate.DeviceStateManager import android.os.Handler @@ -39,6 +41,7 @@ constructor( private val hingeAngleProvider: HingeAngleProvider, private val screenStatusProvider: ScreenStatusProvider, private val deviceStateManager: DeviceStateManager, + private val activityManager: ActivityManager, @Main private val mainExecutor: Executor, @Main private val handler: Handler ) : FoldStateProvider { @@ -92,10 +95,12 @@ constructor( } val isClosing = angle < lastHingeAngle + val closingThreshold = getClosingThreshold() + val closingThresholdMet = closingThreshold == null || angle < closingThreshold val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES val closingEventDispatched = lastFoldUpdate == FOLD_UPDATE_START_CLOSING - if (isClosing && !closingEventDispatched && !isFullyOpened) { + if (isClosing && closingThresholdMet && !closingEventDispatched && !isFullyOpened) { notifyFoldUpdate(FOLD_UPDATE_START_CLOSING) } @@ -113,6 +118,33 @@ constructor( outputListeners.forEach { it.onHingeAngleUpdate(angle) } } + /** + * Fold animation should be started only after the threshold returned here. + * + * This has been introduced because the fold animation might be distracting/unwanted on top of + * apps that support table-top/HALF_FOLDED mode. Only for launcher, there is no threshold. + */ + private fun getClosingThreshold(): Int? { + val activityType = + activityManager + .getRunningTasks(/* maxNum= */ 1) + ?.getOrNull(0) + ?.configuration + ?.windowConfiguration + ?.activityType + ?: return null + + if (DEBUG) { + Log.d(TAG, "activityType=" + activityType) + } + + return if (activityType == ACTIVITY_TYPE_HOME) { + null + } else { + START_CLOSING_ON_APPS_THRESHOLD_DEGREES + } + } + private inner class FoldStateListener(context: Context) : DeviceStateManager.FoldStateListener( context, @@ -199,7 +231,10 @@ private const val DEBUG = false * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a * [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not reached. */ -@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 1000L +@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 600L /** Threshold after which we consider the device fully unfolded. */ @VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f + +/** Fold animation on top of apps only when the angle exceeds this threshold. */ +@VisibleForTesting const val START_CLOSING_ON_APPS_THRESHOLD_DEGREES = 60 diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 46a883194e25..3103219d8978 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -307,8 +307,6 @@ public class KeyguardSecurityContainer extends FrameLayout { void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback); updateBiometricRetry(securityMode, faceAuthEnabled); - - setupViewMode(); } void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager, @@ -1044,11 +1042,13 @@ public class KeyguardSecurityContainer extends FrameLayout { /** * Moves the bouncer to align with a tap (most likely in the shade), so the bouncer - * appears on the same side as a touch. Will not update the user-preference. + * appears on the same side as a touch. */ @Override public void updatePositionByTouchX(float x) { - updateSecurityViewLocation(x <= mView.getWidth() / 2f, /* animate= */false); + boolean isTouchOnLeft = x <= mView.getWidth() / 2f; + updateSideSetting(isTouchOnLeft); + updateSecurityViewLocation(isTouchOnLeft, /* animate= */false); } boolean isLeftAligned() { @@ -1057,6 +1057,13 @@ public class KeyguardSecurityContainer extends FrameLayout { == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT; } + private void updateSideSetting(boolean leftAligned) { + mGlobalSettings.putInt( + Settings.Global.ONE_HANDED_KEYGUARD_SIDE, + leftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT + : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT); + } + /** * Determine if a tap on this view is on the other side. If so, will animate positions * and record the preference to always show on this side. @@ -1070,10 +1077,7 @@ public class KeyguardSecurityContainer extends FrameLayout { || (!currentlyLeftAligned && (x < mView.getWidth() / 2f))) { boolean willBeLeftAligned = !currentlyLeftAligned; - mGlobalSettings.putInt( - Settings.Global.ONE_HANDED_KEYGUARD_SIDE, - willBeLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT - : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT); + updateSideSetting(willBeLeftAligned); int keyguardState = willBeLeftAligned ? SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SWITCH_LEFT diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 57997d8efd6f..1a325d3586f4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -233,6 +233,13 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mSecurityViewFlipperController.reloadColors(); } }; + private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onDevicePolicyManagerStateChanged() { + showPrimarySecurityScreen(false); + } + }; private KeyguardSecurityContainerController(KeyguardSecurityContainer view, AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory, @@ -279,6 +286,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard @Override protected void onViewAttached() { + mUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); mView.setSwipeListener(mSwipeListener); mView.addMotionEventListener(mGlobalTouchListener); mConfigurationController.addCallback(mConfigurationListener); @@ -286,6 +294,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard @Override protected void onViewDetached() { + mUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); mConfigurationController.removeCallback(mConfigurationListener); mView.removeMotionEventListener(mGlobalTouchListener); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 5602f3d3801b..fcabbbca6e34 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2723,12 +2723,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** - * Handle {@link #MSG_DPM_STATE_CHANGED} + * Handle {@link #MSG_DPM_STATE_CHANGED} which can change primary authentication methods to + * pin/pattern/password/none. */ private void handleDevicePolicyManagerStateChanged(int userId) { Assert.isMainThread(); updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); updateSecondaryLockscreenRequirement(userId); + + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onDevicePolicyManagerStateChanged(); + } + } } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index ad2053cbc31b..9373ea8f459c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -300,6 +300,11 @@ public class KeyguardUpdateMonitorCallback { public void onSecondaryLockscreenRequirementChanged(int userId) { } /** + * Called when device policy manager state changes. + */ + public void onDevicePolicyManagerStateChanged() { } + + /** * Called when notifying user to unlock in order to use NFC. */ public void onRequireUnlockForNfc() { } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt index 011881354e35..22c69373336f 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt @@ -369,15 +369,10 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec * Update the rounded corner size. */ fun updateRoundedCornerSize(top: Int, bottom: Int) { - if (roundedCornerTopSize == top && roundedCornerBottomSize == bottom) { - return - } roundedCornerTopSize = top roundedCornerBottomSize = bottom updateRoundedCornerDrawableBounds() - - // Use requestLayout() to trigger transparent region recalculated - requestLayout() + invalidate() } private fun updateRoundedCornerDrawableBounds() { diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 5de09b13bf6a..2f5292cec909 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -77,7 +77,6 @@ import com.android.systemui.decor.DecorProviderFactory; import com.android.systemui.decor.DecorProviderKt; import com.android.systemui.decor.OverlayWindow; import com.android.systemui.decor.PrivacyDotDecorProviderFactory; -import com.android.systemui.decor.RoundedCornerDecorProviderFactory; import com.android.systemui.decor.RoundedCornerResDelegate; import com.android.systemui.qs.SettingObserver; import com.android.systemui.settings.UserTracker; @@ -139,9 +138,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab @VisibleForTesting protected RoundedCornerResDelegate mRoundedCornerResDelegate; @VisibleForTesting - protected DecorProviderFactory mRoundedCornerFactory; - private int mProviderRefreshToken = 0; - @VisibleForTesting protected OverlayWindow[] mOverlays = null; @Nullable private DisplayCutoutView[] mCutoutViews; @@ -296,11 +292,11 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mDisplayUniqueId = mContext.getDisplay().getUniqueId(); mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(), mDisplayUniqueId); - mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate); mWindowManager = mContext.getSystemService(WindowManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class); mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport(); - updateHwLayerRoundedCornerDrawable(); + updateRoundedCornerDrawable(); + updateRoundedCornerRadii(); setupDecorations(); setupCameraListener(); @@ -352,7 +348,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab final String newUniqueId = mContext.getDisplay().getUniqueId(); if (!Objects.equals(newUniqueId, mDisplayUniqueId)) { mDisplayUniqueId = newUniqueId; - mRoundedCornerResDelegate.updateDisplayUniqueId(newUniqueId, null); + mRoundedCornerResDelegate.reloadAll(newUniqueId); final DisplayDecorationSupport newScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport(); // When the value of mSupportHwcScreenDecoration is changed, re-setup the whole @@ -363,12 +359,12 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab setupDecorations(); return; } - updateHwLayerRoundedCornerDrawable(); + updateRoundedCornerDrawable(); } if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.onDisplayChanged(displayId); } - updateView(); + updateOrientation(); } }; @@ -410,22 +406,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } private void setupDecorations() { - if (hasRoundedCorners() || shouldDrawCutout() || isPrivacyDotEnabled()) { - List<DecorProvider> decorProviders = new ArrayList<>(mDotFactory.getProviders()); + List<DecorProvider> decorProviders = mDotFactory.getProviders(); + + if (hasRoundedCorners() || shouldDrawCutout() || !decorProviders.isEmpty()) { if (mHwcScreenDecorationSupport != null) { createHwcOverlay(); } else { removeHwcOverlay(); - decorProviders.addAll(mRoundedCornerFactory.getProviders()); } final DisplayCutout cutout = getCutout(); for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { - if (shouldShowSwLayerCutout(i, cutout) || shouldShowSwLayerRoundedCorner(i, cutout) - || shouldShowSwLayerPrivacyDot(i, cutout)) { + if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout) + || shouldShowPrivacyDot(i, cutout)) { Pair<List<DecorProvider>, List<DecorProvider>> pair = DecorProviderKt.partitionAlignedBound(decorProviders, i); decorProviders = pair.getSecond(); - createOverlay(i, pair.getFirst()); + createOverlay(i, cutout, pair.getFirst()); } else { removeOverlay(i); } @@ -526,6 +522,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab private void createOverlay( @BoundsPosition int pos, + @Nullable DisplayCutout cutout, @NonNull List<DecorProvider> decorProviders) { if (mOverlays == null) { mOverlays = new OverlayWindow[BOUNDS_POSITION_LENGTH]; @@ -550,7 +547,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mCutoutViews[pos] = new DisplayCutoutView(mContext, pos); mCutoutViews[pos].setColor(mTintColor); overlayView.addView(mCutoutViews[pos]); - mCutoutViews[pos].updateRotation(mRotation); + updateView(pos, cutout); } mWindowManager.addView(overlayView, getWindowLayoutParams(pos)); @@ -606,7 +603,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab private OverlayWindow overlayForPosition( @BoundsPosition int pos, @NonNull List<DecorProvider> decorProviders) { - final OverlayWindow currentOverlay = new OverlayWindow(mContext); + final OverlayWindow currentOverlay = new OverlayWindow(LayoutInflater.from(mContext), pos); decorProviders.forEach(provider -> { removeOverlayView(provider.getViewId()); currentOverlay.addDecorProvider(provider, mRotation); @@ -620,16 +617,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab return currentOverlay; } - private void updateView() { - if (mOverlays == null) { + private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { + if (mOverlays == null || mOverlays[pos] == null || mHwcScreenDecorationSupport != null) { return; } - ++mProviderRefreshToken; - for (final OverlayWindow overlay: mOverlays) { - if (overlay == null) { - continue; - } - overlay.onReloadResAndMeasure(null, mProviderRefreshToken, mRotation, mDisplayUniqueId); + + // update rounded corner view rotation + updateRoundedCornerView(pos, R.id.left, cutout); + updateRoundedCornerView(pos, R.id.right, cutout); + updateRoundedCornerSize( + mRoundedCornerResDelegate.getTopRoundedSize(), + mRoundedCornerResDelegate.getBottomRoundedSize()); + updateRoundedCornerImageView(); + + // update cutout view rotation + if (mCutoutViews != null && mCutoutViews[pos] != null) { + mCutoutViews[pos].updateRotation(mRotation); } } @@ -803,6 +806,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab int oldRotation = mRotation; mPendingRotationChange = false; updateOrientation(); + updateRoundedCornerRadii(); if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation); setupDecorations(); if (mOverlays != null) { @@ -862,32 +866,109 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mDotViewController.setNewRotation(newRotation); } - if (!mPendingRotationChange && newRotation != mRotation) { + if (mPendingRotationChange) { + return; + } + if (newRotation != mRotation) { mRotation = newRotation; if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.pendingRotationChange = false; mScreenDecorHwcLayer.updateRotation(mRotation); - updateHwLayerRoundedCornerSize(); - updateHwLayerRoundedCornerDrawable(); } - updateLayoutParams(); - // update cutout view rotation - if (mCutoutViews != null) { - for (final DisplayCutoutView cutoutView: mCutoutViews) { - if (cutoutView == null) { + if (mOverlays != null) { + updateLayoutParams(); + final DisplayCutout cutout = getCutout(); + for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { + if (mOverlays[i] == null) { continue; } - cutoutView.updateRotation(mRotation); + updateView(i, cutout); } } } + } + + private void updateRoundedCornerRadii() { + // We should eventually move to just using the intrinsic size of the drawables since + // they should be sized to the exact pixels they want to cover. Therefore I'm purposely not + // upgrading all of the configs to contain (width, height) pairs. Instead assume that a + // device configured using the single integer config value is okay with drawing the corners + // as a square + final Size oldRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize(); + final Size oldRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize(); + mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId); + final Size newRoundedDefaultTop = mRoundedCornerResDelegate.getTopRoundedSize(); + final Size newRoundedDefaultBottom = mRoundedCornerResDelegate.getBottomRoundedSize(); + + if (oldRoundedDefaultTop.getWidth() != newRoundedDefaultTop.getWidth() + || oldRoundedDefaultBottom.getWidth() != newRoundedDefaultBottom.getWidth()) { + onTuningChanged(SIZE, null); + } + } + + private void updateRoundedCornerView(@BoundsPosition int pos, int id, + @Nullable DisplayCutout cutout) { + final View rounded = mOverlays[pos].getRootView().findViewById(id); + if (rounded == null) { + return; + } + rounded.setVisibility(View.GONE); + if (shouldShowRoundedCorner(pos, cutout)) { + final int gravity = getRoundedCornerGravity(pos, id == R.id.left); + ((FrameLayout.LayoutParams) rounded.getLayoutParams()).gravity = gravity; + setRoundedCornerOrientation(rounded, gravity); + rounded.setVisibility(View.VISIBLE); + } + } - // update views - updateView(); + private int getRoundedCornerGravity(@BoundsPosition int pos, boolean isStart) { + final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); + switch (rotatedPos) { + case BOUNDS_POSITION_LEFT: + return isStart ? Gravity.TOP | Gravity.LEFT : Gravity.BOTTOM | Gravity.LEFT; + case BOUNDS_POSITION_TOP: + return isStart ? Gravity.TOP | Gravity.LEFT : Gravity.TOP | Gravity.RIGHT; + case BOUNDS_POSITION_RIGHT: + return isStart ? Gravity.TOP | Gravity.RIGHT : Gravity.BOTTOM | Gravity.RIGHT; + case BOUNDS_POSITION_BOTTOM: + return isStart ? Gravity.BOTTOM | Gravity.LEFT : Gravity.BOTTOM | Gravity.RIGHT; + default: + throw new IllegalArgumentException("Incorrect position: " + rotatedPos); + } } + /** + * Configures the rounded corner drawable's view matrix based on the gravity. + * + * The gravity describes which corner to configure for, and the drawable we are rotating is + * assumed to be oriented for the top-left corner of the device regardless of the target corner. + * Therefore we need to rotate 180 degrees to get a bottom-left corner, and mirror in the x- or + * y-axis for the top-right and bottom-left corners. + */ + private void setRoundedCornerOrientation(View corner, int gravity) { + corner.setRotation(0); + corner.setScaleX(1); + corner.setScaleY(1); + switch (gravity) { + case Gravity.TOP | Gravity.LEFT: + return; + case Gravity.TOP | Gravity.RIGHT: + corner.setScaleX(-1); // flip X axis + return; + case Gravity.BOTTOM | Gravity.LEFT: + corner.setScaleY(-1); // flip Y axis + return; + case Gravity.BOTTOM | Gravity.RIGHT: + corner.setRotation(180); + return; + default: + throw new IllegalArgumentException("Unsupported gravity: " + gravity); + } + } private boolean hasRoundedCorners() { - return mRoundedCornerFactory.getHasProviders(); + return mRoundedCornerResDelegate.getBottomRoundedSize().getWidth() > 0 + || mRoundedCornerResDelegate.getTopRoundedSize().getWidth() > 0 + || mRoundedCornerResDelegate.isMultipleRadius(); } private boolean isDefaultShownOverlayPos(@BoundsPosition int pos, @@ -906,19 +987,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } } - private boolean shouldShowSwLayerRoundedCorner(@BoundsPosition int pos, + private boolean shouldShowRoundedCorner(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout) && mHwcScreenDecorationSupport == null; } - private boolean shouldShowSwLayerPrivacyDot(@BoundsPosition int pos, - @Nullable DisplayCutout cutout) { + private boolean shouldShowPrivacyDot(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout); } - private boolean shouldShowSwLayerCutout(@BoundsPosition int pos, - @Nullable DisplayCutout cutout) { + private boolean shouldShowCutout(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll(); final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); return (bounds != null && !bounds[rotatedPos].isEmpty() @@ -953,33 +1032,54 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab return; } mExecutor.execute(() -> { - if (mOverlays == null || !SIZE.equals(key)) { - return; - } - ++mProviderRefreshToken; - try { - final int sizeFactor = Integer.parseInt(newValue); - mRoundedCornerResDelegate.updateTuningSizeFactor(sizeFactor, mProviderRefreshToken); - } catch (NumberFormatException e) { - mRoundedCornerResDelegate.updateTuningSizeFactor(null, mProviderRefreshToken); - } - Integer[] filterIds = { - R.id.rounded_corner_top_left, - R.id.rounded_corner_top_right, - R.id.rounded_corner_bottom_left, - R.id.rounded_corner_bottom_right - }; - for (final OverlayWindow overlay: mOverlays) { - if (overlay == null) { - continue; + if (mOverlays == null) return; + if (SIZE.equals(key)) { + if (newValue != null) { + try { + mRoundedCornerResDelegate.updateTuningSizeFactor( + Integer.parseInt(newValue)); + } catch (Exception e) { + } } - overlay.onReloadResAndMeasure(filterIds, mProviderRefreshToken, mRotation, - mDisplayUniqueId); + updateRoundedCornerSize( + mRoundedCornerResDelegate.getTopRoundedSize(), + mRoundedCornerResDelegate.getBottomRoundedSize()); } - updateHwLayerRoundedCornerSize(); }); } + private void updateRoundedCornerDrawable() { + mRoundedCornerResDelegate.reloadAll(mDisplayUniqueId); + updateRoundedCornerImageView(); + } + + private void updateRoundedCornerImageView() { + final Drawable top = mRoundedCornerResDelegate.getTopRoundedDrawable(); + final Drawable bottom = mRoundedCornerResDelegate.getBottomRoundedDrawable(); + + if (mScreenDecorHwcLayer != null) { + mScreenDecorHwcLayer.updateRoundedCornerDrawable(top, bottom); + return; + } + + if (mOverlays == null) { + return; + } + final ColorStateList colorStateList = ColorStateList.valueOf(mTintColor); + for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { + if (mOverlays[i] == null) { + continue; + } + final ViewGroup overlayView = mOverlays[i].getRootView(); + ((ImageView) overlayView.findViewById(R.id.left)).setImageTintList(colorStateList); + ((ImageView) overlayView.findViewById(R.id.right)).setImageTintList(colorStateList); + ((ImageView) overlayView.findViewById(R.id.left)).setImageDrawable( + isTopRoundedCorner(i, R.id.left) ? top : bottom); + ((ImageView) overlayView.findViewById(R.id.right)).setImageDrawable( + isTopRoundedCorner(i, R.id.right) ? top : bottom); + } + } + private void updateHwLayerRoundedCornerDrawable() { if (mScreenDecorHwcLayer == null) { return; @@ -994,6 +1094,25 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mScreenDecorHwcLayer.updateRoundedCornerDrawable(topDrawable, bottomDrawable); } + @VisibleForTesting + boolean isTopRoundedCorner(@BoundsPosition int pos, int id) { + switch (pos) { + case BOUNDS_POSITION_LEFT: + case BOUNDS_POSITION_RIGHT: + if (mRotation == ROTATION_270) { + return id == R.id.left ? false : true; + } else { + return id == R.id.left ? true : false; + } + case BOUNDS_POSITION_TOP: + return true; + case BOUNDS_POSITION_BOTTOM: + return false; + default: + throw new IllegalArgumentException("Unknown bounds position"); + } + } + private void updateHwLayerRoundedCornerSize() { if (mScreenDecorHwcLayer == null) { return; @@ -1005,6 +1124,28 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mScreenDecorHwcLayer.updateRoundedCornerSize(topWidth, bottomWidth); } + private void updateRoundedCornerSize(Size sizeTop, Size sizeBottom) { + + if (mScreenDecorHwcLayer != null) { + mScreenDecorHwcLayer.updateRoundedCornerSize(sizeTop.getWidth(), sizeBottom.getWidth()); + return; + } + + if (mOverlays == null) { + return; + } + for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { + if (mOverlays[i] == null) { + continue; + } + final ViewGroup overlayView = mOverlays[i].getRootView(); + setSize(overlayView.findViewById(R.id.left), + isTopRoundedCorner(i, R.id.left) ? sizeTop : sizeBottom); + setSize(overlayView.findViewById(R.id.right), + isTopRoundedCorner(i, R.id.right) ? sizeTop : sizeBottom); + } + } + @VisibleForTesting protected void setSize(View view, Size pixelSize) { LayoutParams params = view.getLayoutParams(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt index 4c00735ab785..085bcfafdf78 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt @@ -33,6 +33,8 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal import android.hardware.fingerprint.ISidefpsController import android.os.Handler import android.util.Log +import android.view.View.AccessibilityDelegate +import android.view.accessibility.AccessibilityEvent import android.view.Display import android.view.Gravity import android.view.LayoutInflater @@ -181,6 +183,23 @@ class SidefpsController @Inject constructor( } lottie.addOverlayDynamicColor(context) + /** + * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from + * speaking @string/accessibility_fingerprint_label twice when sensor location indicator + * is in focus + */ + view.setAccessibilityDelegate(object : AccessibilityDelegate() { + override fun dispatchPopulateAccessibilityEvent( + host: View, + event: AccessibilityEvent + ): Boolean { + return if (event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + true + } else { + super.dispatchPopulateAccessibilityEvent(host, event) + } + } + }) return view } diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt index bbb75c3521c1..0ff5805ab111 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -60,6 +60,8 @@ private const val DEBUG = true * Use only for IntentFilters with actions and optionally categories. It does not support, * permissions, schemes, data types, data authorities or priority different than 0. * Cannot be used for getting sticky broadcasts (either as return of registering or as re-delivery). + * Broadcast handling may be asynchronous *without* calling goAsync(), as it's running within sysui + * and doesn't need to worry about being killed. */ open class BroadcastDispatcher constructor ( private val context: Context, diff --git a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt index 03ee8b11ab41..3543bb4ab9e9 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt @@ -15,8 +15,8 @@ */ package com.android.systemui.decor -import android.content.Context import android.view.DisplayCutout +import android.view.LayoutInflater import android.view.Surface import android.view.View import android.view.ViewGroup @@ -38,20 +38,9 @@ abstract class DecorProvider { /** The aligned bounds for the view which is created through inflateView() */ abstract val alignedBounds: List<Int> - /** - * Called when res info changed. - * Child provider needs to implement it if its view needs to be updated. - */ - abstract fun onReloadResAndMeasure( - view: View, - reloadToken: Int, - @Surface.Rotation rotation: Int, - displayUniqueId: String? = null - ) - /** Inflate view into parent as current rotation */ abstract fun inflateView( - context: Context, + inflater: LayoutInflater, parent: ViewGroup, @Surface.Rotation rotation: Int ): View diff --git a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt index f38ff14726ca..9f8679cdea4a 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt @@ -16,22 +16,31 @@ package com.android.systemui.decor import android.annotation.IdRes -import android.content.Context +import android.view.DisplayCutout +import android.view.LayoutInflater import android.view.Surface import android.view.View import android.view.ViewGroup -import com.android.systemui.RegionInterceptingFrameLayout +import com.android.systemui.R +import java.util.HashMap -class OverlayWindow(private val context: Context) { +class OverlayWindow(private val layoutInflater: LayoutInflater, private val pos: Int) { - val rootView = RegionInterceptingFrameLayout(context) as ViewGroup - private val viewProviderMap = mutableMapOf<Int, Pair<View, DecorProvider>>() + private val layoutId: Int + get() { + return if (pos == DisplayCutout.BOUNDS_POSITION_LEFT || + pos == DisplayCutout.BOUNDS_POSITION_TOP) { + R.layout.rounded_corners_top + } else { + R.layout.rounded_corners_bottom + } + } + + val rootView = layoutInflater.inflate(layoutId, null) as ViewGroup + private val viewProviderMap: MutableMap<Int, Pair<View, DecorProvider>> = HashMap() - fun addDecorProvider( - decorProvider: DecorProvider, - @Surface.Rotation rotation: Int - ) { - val view = decorProvider.inflateView(context, rootView, rotation) + fun addDecorProvider(decorProvider: DecorProvider, @Surface.Rotation rotation: Int) { + val view = decorProvider.inflateView(layoutInflater, rootView, rotation) viewProviderMap[decorProvider.viewId] = Pair(view, decorProvider) } @@ -47,35 +56,4 @@ class OverlayWindow(private val context: Context) { viewProviderMap.remove(id) } } - - /** - * Apply new configuration info into views. - * @param filterIds target view ids. Apply to all if null. - * @param rotation current or new rotation direction. - * @param displayUniqueId new displayUniqueId if any. - */ - fun onReloadResAndMeasure( - filterIds: Array<Int>? = null, - reloadToken: Int, - @Surface.Rotation rotation: Int, - displayUniqueId: String? = null - ) { - filterIds?.forEach { id -> - viewProviderMap[id]?.let { - it.second.onReloadResAndMeasure( - view = it.first, - reloadToken = reloadToken, - displayUniqueId = displayUniqueId, - rotation = rotation) - } - } ?: run { - viewProviderMap.values.forEach { - it.second.onReloadResAndMeasure( - view = it.first, - reloadToken = reloadToken, - displayUniqueId = displayUniqueId, - rotation = rotation) - } - } - } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt index 136f135af759..7afd7e0eedc5 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt @@ -16,7 +16,6 @@ package com.android.systemui.decor -import android.content.Context import android.content.res.Resources import android.view.DisplayCutout import android.view.LayoutInflater @@ -77,21 +76,12 @@ class PrivacyDotCornerDecorProviderImpl( private val layoutId: Int ) : CornerDecorProvider() { - override fun onReloadResAndMeasure( - view: View, - reloadToken: Int, - rotation: Int, - displayUniqueId: String? - ) { - // Do nothing here because it is handled inside PrivacyDotViewController - } - override fun inflateView( - context: Context, + inflater: LayoutInflater, parent: ViewGroup, @Surface.Rotation rotation: Int ): View { - LayoutInflater.from(context).inflate(layoutId, parent, true) + inflater.inflate(layoutId, parent, true) return parent.getChildAt(parent.childCount - 1 /* latest new added child */) } } diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt deleted file mode 100644 index 4388b8b3b92d..000000000000 --- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.decor - -import android.view.DisplayCutout -import com.android.systemui.R - -class RoundedCornerDecorProviderFactory( - private val roundedCornerResDelegate: RoundedCornerResDelegate -) : DecorProviderFactory() { - - override val hasProviders: Boolean - get() = roundedCornerResDelegate.run { - // We don't consider isMultipleRadius here because it makes no sense if size is zero. - topRoundedSize.width > 0 || bottomRoundedSize.width > 0 - } - - override val providers: List<DecorProvider> - get() { - val hasTop = roundedCornerResDelegate.topRoundedSize.width > 0 - val hasBottom = roundedCornerResDelegate.bottomRoundedSize.width > 0 - return when { - hasTop && hasBottom -> listOf( - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_top_left, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT, - roundedCornerResDelegate = roundedCornerResDelegate), - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_top_right, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT, - roundedCornerResDelegate = roundedCornerResDelegate), - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_bottom_left, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT, - roundedCornerResDelegate = roundedCornerResDelegate), - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_bottom_right, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT, - roundedCornerResDelegate = roundedCornerResDelegate) - ) - hasTop -> listOf( - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_top_left, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT, - roundedCornerResDelegate = roundedCornerResDelegate), - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_top_right, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT, - roundedCornerResDelegate = roundedCornerResDelegate) - ) - hasBottom -> listOf( - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_bottom_left, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT, - roundedCornerResDelegate = roundedCornerResDelegate), - RoundedCornerDecorProviderImpl( - viewId = R.id.rounded_corner_bottom_right, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT, - roundedCornerResDelegate = roundedCornerResDelegate) - ) - else -> emptyList() - } - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt deleted file mode 100644 index 90ff950406b4..000000000000 --- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.decor - -import android.content.Context -import android.view.DisplayCutout -import android.view.Gravity -import android.view.Surface -import android.view.View -import android.view.ViewGroup -import android.widget.FrameLayout -import android.widget.ImageView -import com.android.systemui.R - -class RoundedCornerDecorProviderImpl( - override val viewId: Int, - @DisplayCutout.BoundsPosition override val alignedBound1: Int, - @DisplayCutout.BoundsPosition override val alignedBound2: Int, - private val roundedCornerResDelegate: RoundedCornerResDelegate -) : CornerDecorProvider() { - - private val isTop = alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP) - - override fun inflateView( - context: Context, - parent: ViewGroup, - @Surface.Rotation rotation: Int - ): View { - return ImageView(context).also { view -> - // View - view.id = viewId - initView(view, rotation) - - // LayoutParams - val layoutSize = if (isTop) { - roundedCornerResDelegate.topRoundedSize - } else { - roundedCornerResDelegate.bottomRoundedSize - } - val params = FrameLayout.LayoutParams( - layoutSize.width, - layoutSize.height, - alignedBound1.toLayoutGravity(rotation) or - alignedBound2.toLayoutGravity(rotation)) - - // AddView - parent.addView(view, params) - } - } - - private fun initView(view: ImageView, @Surface.Rotation rotation: Int) { - view.setRoundedCornerImage(roundedCornerResDelegate, isTop) - view.adjustRotation(alignedBounds, rotation) - view.setColorFilter(IMAGE_TINT_COLOR) - } - - override fun onReloadResAndMeasure( - view: View, - reloadToken: Int, - @Surface.Rotation rotation: Int, - displayUniqueId: String? - ) { - roundedCornerResDelegate.updateDisplayUniqueId(displayUniqueId, reloadToken) - - initView((view as ImageView), rotation) - - val layoutSize = if (isTop) { - roundedCornerResDelegate.topRoundedSize - } else { - roundedCornerResDelegate.bottomRoundedSize - } - (view.layoutParams as FrameLayout.LayoutParams).let { - it.width = layoutSize.width - it.height = layoutSize.height - it.gravity = alignedBound1.toLayoutGravity(rotation) or - alignedBound2.toLayoutGravity(rotation) - view.setLayoutParams(it) - } - } -} - -private const val IMAGE_TINT_COLOR: Int = 0xFF000000.toInt() - -@DisplayCutout.BoundsPosition -private fun Int.toLayoutGravity(@Surface.Rotation rotation: Int): Int = when (rotation) { - Surface.ROTATION_0 -> when (this) { - DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.LEFT - DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.TOP - DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.RIGHT - else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.BOTTOM - } - Surface.ROTATION_90 -> when (this) { - DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.BOTTOM - DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.LEFT - DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.TOP - else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.LEFT - } - Surface.ROTATION_270 -> when (this) { - DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.TOP - DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.RIGHT - DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.BOTTOM - else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.LEFT - } - else /* Surface.ROTATION_180 */ -> when (this) { - DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.RIGHT - DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.BOTTOM - DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.LEFT - else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.TOP - } -} - -private fun ImageView.setRoundedCornerImage( - resDelegate: RoundedCornerResDelegate, - isTop: Boolean -) { - val drawable = if (isTop) - resDelegate.topRoundedDrawable - else - resDelegate.bottomRoundedDrawable - - if (drawable != null) { - setImageDrawable(drawable) - } else { - setImageResource( - if (isTop) - R.drawable.rounded_corner_top - else - R.drawable.rounded_corner_bottom - ) - } -} - -/** - * Configures the rounded corner drawable's view matrix based on the gravity. - * - * The gravity describes which corner to configure for, and the drawable we are rotating is assumed - * to be oriented for the top-left corner of the device regardless of the target corner. - * Therefore we need to rotate 180 degrees to get a bottom-left corner, and mirror in the x- or - * y-axis for the top-right and bottom-left corners. - */ -private fun ImageView.adjustRotation(alignedBounds: List<Int>, @Surface.Rotation rotation: Int) { - var newRotation = 0F - var newScaleX = 1F - var newScaleY = 1F - - val isTop = alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP) - val isLeft = alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT) - when (rotation) { - Surface.ROTATION_0 -> when { - isTop && isLeft -> {} - isTop && !isLeft -> { newScaleX = -1F } - !isTop && isLeft -> { newScaleY = -1F } - else /* !isTop && !isLeft */ -> { newRotation = 180F } - } - Surface.ROTATION_90 -> when { - isTop && isLeft -> { newScaleY = -1F } - isTop && !isLeft -> {} - !isTop && isLeft -> { newRotation = 180F } - else /* !isTop && !isLeft */ -> { newScaleX = -1F } - } - Surface.ROTATION_270 -> when { - isTop && isLeft -> { newScaleX = -1F } - isTop && !isLeft -> { newRotation = 180F } - !isTop && isLeft -> {} - else /* !isTop && !isLeft */ -> { newScaleY = -1F } - } - else /* Surface.ROTATION_180 */ -> when { - isTop && isLeft -> { newRotation = 180F } - isTop && !isLeft -> { newScaleY = -1F } - !isTop && isLeft -> { newScaleX = -1F } - else /* !isTop && !isLeft */ -> {} - } - } - - this.rotation = newRotation - this.scaleX = newScaleX - this.scaleY = newScaleY -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt index 1d38e58dd48c..c817f89c7a9b 100644 --- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt @@ -36,8 +36,6 @@ class RoundedCornerResDelegate( private val density: Float get() = res.displayMetrics.density - private var reloadToken: Int = 0 - var isMultipleRadius: Boolean = false private set @@ -62,26 +60,12 @@ class RoundedCornerResDelegate( reloadMeasures() } - private fun reloadAll(newReloadToken: Int) { - if (reloadToken == newReloadToken) { - return - } - reloadToken = newReloadToken + fun reloadAll(newDisplayUniqueId: String?) { + displayUniqueId = newDisplayUniqueId reloadDrawables() reloadMeasures() } - fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) { - if (displayUniqueId != newDisplayUniqueId) { - displayUniqueId = newDisplayUniqueId - newReloadToken ?.let { reloadToken = it } - reloadDrawables() - reloadMeasures() - } else { - newReloadToken?.let { reloadAll(it) } - } - } - private fun reloadDrawables() { val configIdx = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId) isMultipleRadius = getIsMultipleRadius(configIdx) @@ -101,9 +85,7 @@ class RoundedCornerResDelegate( arrayResId = R.array.config_roundedCornerBottomDrawableArray, backupDrawableId = R.drawable.rounded_corner_bottom ) ?: roundedDrawable - } - private fun reloadMeasures(roundedSizeFactor: Int? = null) { // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius if (isMultipleRadius) { @@ -131,19 +113,44 @@ class RoundedCornerResDelegate( if (bottomRoundedSize.width == 0) { bottomRoundedSize = roundedSize } + } - if (roundedSizeFactor != null && roundedSizeFactor > 0) { - val length: Int = (roundedSizeFactor * density).toInt() - topRoundedSize = Size(length, length) - bottomRoundedSize = Size(length, length) + private fun reloadMeasures(roundedSizeFactor: Int? = null) { + // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the + // (width, height) size of drawable/rounded.xml instead of rounded_corner_radius + if (isMultipleRadius) { + roundedSize = Size( + roundedDrawable?.intrinsicWidth ?: 0, + roundedDrawable?.intrinsicHeight ?: 0) + topRoundedDrawable?.let { + topRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight) + } + bottomRoundedDrawable?.let { + bottomRoundedSize = Size(it.intrinsicWidth, it.intrinsicHeight) + } + } else { + val defaultRadius = RoundedCorners.getRoundedCornerRadius(res, displayUniqueId) + val topRadius = RoundedCorners.getRoundedCornerTopRadius(res, displayUniqueId) + val bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(res, displayUniqueId) + roundedSize = Size(defaultRadius, defaultRadius) + topRoundedSize = Size(topRadius, topRadius) + bottomRoundedSize = Size(bottomRadius, bottomRadius) } - } - fun updateTuningSizeFactor(factor: Int?, newReloadToken: Int) { - if (reloadToken == newReloadToken) { - return + roundedSizeFactor ?.let { + val length: Int = (it * density).toInt() + roundedSize = Size(length, length) } - reloadToken = newReloadToken + + if (topRoundedSize.width == 0) { + topRoundedSize = roundedSize + } + if (bottomRoundedSize.width == 0) { + bottomRoundedSize = roundedSize + } + } + + fun updateTuningSizeFactor(factor: Int) { reloadMeasures(factor) } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java new file mode 100644 index 000000000000..aaa34ed32c7e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayNotificationCountProvider.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dreams; + +import android.annotation.NonNull; +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; + +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationListener.NotificationHandler; +import com.android.systemui.statusbar.policy.CallbackController; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +/*** + * {@link DreamOverlayNotificationCountProvider} provides the current notification count to + * registered callbacks. + */ +@SysUISingleton +public class DreamOverlayNotificationCountProvider + implements CallbackController<DreamOverlayNotificationCountProvider.Callback> { + private final Set<String> mNotificationKeys = new HashSet<>(); + private final List<Callback> mCallbacks = new ArrayList<>(); + + private final NotificationHandler mNotificationHandler = new NotificationHandler() { + @Override + public void onNotificationPosted( + StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) { + mNotificationKeys.add(sbn.getKey()); + reportNotificationCountChanged(); + } + + @Override + public void onNotificationRemoved( + StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) { + mNotificationKeys.remove(sbn.getKey()); + reportNotificationCountChanged(); + } + + @Override + public void onNotificationRemoved( + StatusBarNotification sbn, + NotificationListenerService.RankingMap rankingMap, + int reason) { + mNotificationKeys.remove(sbn.getKey()); + reportNotificationCountChanged(); + } + + @Override + public void onNotificationRankingUpdate(NotificationListenerService.RankingMap rankingMap) { + } + + @Override + public void onNotificationsInitialized() { + } + }; + + @Inject + public DreamOverlayNotificationCountProvider( + NotificationListener notificationListener) { + notificationListener.addNotificationHandler(mNotificationHandler); + Arrays.stream(notificationListener.getActiveNotifications()) + .forEach(sbn -> mNotificationKeys.add(sbn.getKey())); + } + + @Override + public void addCallback(@NonNull Callback callback) { + if (!mCallbacks.contains(callback)) { + mCallbacks.add(callback); + callback.onNotificationCountChanged(mNotificationKeys.size()); + } + } + + @Override + public void removeCallback(@NonNull Callback callback) { + mCallbacks.remove(callback); + } + + private void reportNotificationCountChanged() { + final int notificationCount = mNotificationKeys.size(); + mCallbacks.forEach(callback -> callback.onNotificationCountChanged(notificationCount)); + } + + /** + * A callback to be registered with {@link DreamOverlayNotificationCountProvider} to receive + * changes to the current notification count. + */ + public interface Callback { + /** + * Called when the notification count has changed. + * @param count The current notification count. + */ + void onNotificationCountChanged(int count); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java index 761f28c5ac3b..d4909c787d13 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java @@ -27,16 +27,12 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.UserHandle; import android.provider.Settings; -import android.service.notification.NotificationListenerService.RankingMap; -import android.service.notification.StatusBarNotification; import android.text.format.DateFormat; import android.util.PluralsMessageFormatter; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.dagger.DreamOverlayComponent; -import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.NotificationListener.NotificationHandler; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -62,7 +58,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve private final Resources mResources; private final DateFormatUtil mDateFormatUtil; private final IndividualSensorPrivacyController mSensorPrivacyController; - private final NotificationListener mNotificationListener; + private final DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider; private final ZenModeController mZenModeController; private final Executor mMainExecutor; @@ -96,35 +92,6 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback = nextAlarm -> updateAlarmStatusIcon(); - private final NotificationHandler mNotificationHandler = new NotificationHandler() { - @Override - public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { - updateNotificationsStatusIcon(); - } - - @Override - public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { - updateNotificationsStatusIcon(); - } - - @Override - public void onNotificationRemoved( - StatusBarNotification sbn, - RankingMap rankingMap, - int reason) { - updateNotificationsStatusIcon(); - } - - @Override - public void onNotificationRankingUpdate(RankingMap rankingMap) { - } - - @Override - public void onNotificationsInitialized() { - updateNotificationsStatusIcon(); - } - }; - private final ZenModeController.Callback mZenModeCallback = new ZenModeController.Callback() { @Override public void onZenChanged(int zen) { @@ -132,6 +99,14 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve } }; + private final DreamOverlayNotificationCountProvider.Callback mNotificationCountCallback = + notificationCount -> showIcon( + DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS, + notificationCount > 0, + notificationCount > 0 + ? buildNotificationsContentDescription(notificationCount) + : null); + @Inject public DreamOverlayStatusBarViewController( DreamOverlayStatusBarView view, @@ -143,7 +118,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve NextAlarmController nextAlarmController, DateFormatUtil dateFormatUtil, IndividualSensorPrivacyController sensorPrivacyController, - NotificationListener notificationListener, + DreamOverlayNotificationCountProvider dreamOverlayNotificationCountProvider, ZenModeController zenModeController) { super(view); mResources = resources; @@ -154,20 +129,14 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mNextAlarmController = nextAlarmController; mDateFormatUtil = dateFormatUtil; mSensorPrivacyController = sensorPrivacyController; - mNotificationListener = notificationListener; + mDreamOverlayNotificationCountProvider = dreamOverlayNotificationCountProvider; mZenModeController = zenModeController; - - // Handlers can be added to NotificationListener, but apparently they can't be removed. So - // add the handler here in the constructor rather than in onViewAttached to avoid confusion. - mNotificationListener.addNotificationHandler(mNotificationHandler); } @Override protected void onViewAttached() { mIsAttached = true; - updateNotificationsStatusIcon(); - mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback); updateWifiUnavailableStatusIcon(); @@ -180,6 +149,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mZenModeController.addCallback(mZenModeCallback); updatePriorityModeStatusIcon(); + mDreamOverlayNotificationCountProvider.addCallback(mNotificationCountCallback); mTouchInsetSession.addViewToTracking(mView); } @@ -189,6 +159,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve mSensorPrivacyController.removeCallback(mSensorCallback); mNextAlarmController.removeCallback(mNextAlarmCallback); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); + mDreamOverlayNotificationCountProvider.removeCallback(mNotificationCountCallback); mTouchInsetSession.clear(); mIsAttached = false; @@ -231,24 +202,6 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve micBlocked && cameraBlocked); } - private void updateNotificationsStatusIcon() { - if (mView == null) { - // It is possible for this method to be called before the view is attached, which makes - // null-checking necessary. - return; - } - - final StatusBarNotification[] notifications = - mNotificationListener.getActiveNotifications(); - final int notificationCount = notifications != null ? notifications.length : 0; - showIcon( - DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS, - notificationCount > 0, - notificationCount > 0 - ? buildNotificationsContentDescription(notificationCount) - : null); - } - private String buildNotificationsContentDescription(int notificationCount) { return PluralsMessageFormatter.format( mResources, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java index aa433832d462..4065a25dac80 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java @@ -540,13 +540,15 @@ public class ComplicationLayoutEngine implements Complication.VisibilityControll /** * Removes a complication by {@link ComplicationId}. */ - public void removeComplication(ComplicationId id) { - if (!mEntries.containsKey(id)) { + public boolean removeComplication(ComplicationId id) { + final ViewEntry entry = mEntries.remove(id); + + if (entry == null) { Log.e(TAG, "could not find id:" + id); - return; + return false; } - final ViewEntry entry = mEntries.get(id); entry.remove(); + return true; } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index d36bb72e4d3b..758609a541e2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2373,7 +2373,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable, // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report // the next draw from here, so we don't have to wait for window manager to signal // this to our ViewRootImpl. - mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw(); + mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw( + false /* syncBuffer */); mScreenOnCoordinator.setWakeAndUnlocking(false); } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index e1602dbb27a0..b8da46ecfab0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -23,18 +23,22 @@ import android.app.WallpaperColors; import android.app.smartspace.SmartspaceAction; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Rect; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Animatable2; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; import android.os.Process; +import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -64,6 +68,7 @@ import com.android.systemui.util.animation.TransitionLayout; import com.android.systemui.util.time.SystemClock; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; @@ -87,6 +92,7 @@ public class MediaControlPanel { private static final int MEDIA_RECOMMENDATION_MAX_NUM = 6; private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name"; private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND"; + private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME"; // Event types logged by smartspace private static final int SMARTSPACE_CARD_CLICK_EVENT = 760; @@ -633,9 +639,34 @@ public class MediaControlPanel { private void setSemanticButton(final ImageButton button, MediaAction mediaAction, ConstraintSet collapsedSet, ConstraintSet expandedSet, boolean showInCompact) { + AnimationBindHandler animHandler; + if (button.getTag() == null) { + animHandler = new AnimationBindHandler(); + button.setTag(animHandler); + } else { + animHandler = (AnimationBindHandler) button.getTag(); + } + + animHandler.tryExecute(() -> { + bindSemanticButton(animHandler, button, mediaAction, + collapsedSet, expandedSet, showInCompact); + }); + } + + private void bindSemanticButton(final AnimationBindHandler animHandler, + final ImageButton button, MediaAction mediaAction, ConstraintSet collapsedSet, + ConstraintSet expandedSet, boolean showInCompact) { + + animHandler.unregisterAll(); if (mediaAction != null) { - button.setImageIcon(mediaAction.getIcon()); + final Drawable icon = mediaAction.getIcon(); + button.setImageDrawable(icon); button.setContentDescription(mediaAction.getContentDescription()); + final Drawable bgDrawable = mediaAction.getBackground(); + button.setBackground(bgDrawable); + + animHandler.tryRegister(icon); + animHandler.tryRegister(bgDrawable); Runnable action = mediaAction.getAction(); if (action == null) { @@ -647,19 +678,75 @@ public class MediaControlPanel { logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT, /* isRecommendationCard */ false); action.run(); + + if (icon instanceof Animatable) { + ((Animatable) icon).start(); + } + if (bgDrawable instanceof Animatable) { + ((Animatable) bgDrawable).start(); + } } }); } } else { - button.setImageIcon(null); + button.setImageDrawable(null); button.setContentDescription(null); button.setEnabled(false); + button.setBackground(mContext.getDrawable(R.drawable.qs_media_round_button_background)); } setVisibleAndAlpha(collapsedSet, button.getId(), mediaAction != null && showInCompact); setVisibleAndAlpha(expandedSet, button.getId(), mediaAction != null); } + private static class AnimationBindHandler extends Animatable2.AnimationCallback { + private ArrayList<Runnable> mOnAnimationsComplete = new ArrayList<>(); + private ArrayList<Animatable2> mRegistrations = new ArrayList<>(); + + public void tryRegister(Drawable drawable) { + if (drawable instanceof Animatable2) { + Animatable2 anim = (Animatable2) drawable; + anim.registerAnimationCallback(this); + mRegistrations.add(anim); + } + } + + public void unregisterAll() { + for (Animatable2 anim : mRegistrations) { + anim.unregisterAnimationCallback(this); + } + mRegistrations.clear(); + } + + public boolean isAnimationRunning() { + for (Animatable2 anim : mRegistrations) { + if (anim.isRunning()) { + return true; + } + } + return false; + } + + public void tryExecute(Runnable action) { + if (isAnimationRunning()) { + mOnAnimationsComplete.add(action); + } else { + action.run(); + } + } + + @Override + public void onAnimationEnd(Drawable drawable) { + super.onAnimationEnd(drawable); + if (!isAnimationRunning()) { + for (Runnable action : mOnAnimationsComplete) { + action.run(); + } + mOnAnimationsComplete.clear(); + } + } + } + @Nullable private ActivityLaunchAnimator.Controller buildLaunchAnimatorController( TransitionLayout player) { @@ -735,18 +822,33 @@ public class MediaControlPanel { icon.setColorFilter(getGrayscaleFilter()); ImageView headerLogoImageView = mRecommendationViewHolder.getCardIcon(); headerLogoImageView.setImageDrawable(icon); + // Set up media source app's label text. - CharSequence appLabel = packageManager.getApplicationLabel(applicationInfo); - if (appLabel.length() != 0) { + CharSequence appName = getAppName(data.getCardAction()); + if (TextUtils.isEmpty(appName)) { + Intent launchIntent = + packageManager.getLaunchIntentForPackage(data.getPackageName()); + if (launchIntent != null) { + ActivityInfo launchActivity = launchIntent.resolveActivityInfo(packageManager, 0); + appName = launchActivity.loadLabel(packageManager); + } else { + Log.w(TAG, "Package " + data.getPackageName() + + " does not have a main launcher activity. Fallback to full app name"); + appName = packageManager.getApplicationLabel(applicationInfo); + } + } + // Set the app name as card's title. + if (!TextUtils.isEmpty(appName)) { TextView headerTitleText = mRecommendationViewHolder.getCardText(); - headerTitleText.setText(appLabel); + headerTitleText.setText(appName); } + // Set up media rec card's tap action if applicable. setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(), /* interactedSubcardRank */ -1); // Set up media rec card's accessibility label. recommendationCard.setContentDescription( - mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel)); + mContext.getString(R.string.controls_media_smartspace_rec_description, appName)); List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems(); List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers(); @@ -791,12 +893,12 @@ public class MediaControlPanel { mediaCoverImageView.setContentDescription( mContext.getString( R.string.controls_media_smartspace_rec_item_no_artist_description, - recommendation.getTitle(), appLabel)); + recommendation.getTitle(), appName)); } else { mediaCoverImageView.setContentDescription( mContext.getString( R.string.controls_media_smartspace_rec_item_description, - recommendation.getTitle(), artistName, appLabel)); + recommendation.getTitle(), artistName, appName)); } if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) { @@ -978,6 +1080,17 @@ public class MediaControlPanel { }); } + /** Returns the upstream app name if available. */ + @Nullable + private String getAppName(SmartspaceAction action) { + if (action == null || action.getIntent() == null + || action.getIntent().getExtras() == null) { + return null; + } + + return action.getIntent().getExtras().getString(KEY_SMARTSPACE_APP_NAME); + } + /** Returns if the Smartspace action will open the activity in foreground. */ private boolean shouldSmartspaceRecItemOpenInForeground(SmartspaceAction action) { if (action == null || action.getIntent() == null diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt index f1712dbc3f1b..47a0991d3d1e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt @@ -170,9 +170,10 @@ data class MediaButton( /** State of a media action. */ data class MediaAction( - val icon: Icon?, + val icon: Drawable?, val action: Runnable?, - val contentDescription: CharSequence? + val contentDescription: CharSequence?, + val background: Drawable? ) /** State of the media device. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index f457ae74fe83..5c36cab7e3c7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -695,11 +695,12 @@ class MediaDataManager( Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId()) } else { action.getIcon() - }.setTint(themeText) + }.setTint(themeText).loadDrawable(context) val mediaAction = MediaAction( mediaActionIcon, runnable, - action.title) + action.title, + context.getDrawable(R.drawable.qs_media_round_button_background)) actionIcons.add(mediaAction) } } @@ -789,30 +790,34 @@ class MediaDataManager( return when (action) { PlaybackState.ACTION_PLAY -> { MediaAction( - Icon.createWithResource(context, R.drawable.ic_media_play), + context.getDrawable(R.drawable.ic_media_play), { controller.transportControls.play() }, - context.getString(R.string.controls_media_button_play) + context.getString(R.string.controls_media_button_play), + context.getDrawable(R.drawable.ic_media_play_container) ) } PlaybackState.ACTION_PAUSE -> { MediaAction( - Icon.createWithResource(context, R.drawable.ic_media_pause), + context.getDrawable(R.drawable.ic_media_pause), { controller.transportControls.pause() }, - context.getString(R.string.controls_media_button_pause) + context.getString(R.string.controls_media_button_pause), + context.getDrawable(R.drawable.ic_media_pause_container) ) } PlaybackState.ACTION_SKIP_TO_PREVIOUS -> { MediaAction( - Icon.createWithResource(context, R.drawable.ic_media_prev), + context.getDrawable(R.drawable.ic_media_prev), { controller.transportControls.skipToPrevious() }, - context.getString(R.string.controls_media_button_prev) + context.getString(R.string.controls_media_button_prev), + context.getDrawable(R.drawable.qs_media_round_button_background) ) } PlaybackState.ACTION_SKIP_TO_NEXT -> { MediaAction( - Icon.createWithResource(context, R.drawable.ic_media_next), + context.getDrawable(R.drawable.ic_media_next), { controller.transportControls.skipToNext() }, - context.getString(R.string.controls_media_button_next) + context.getString(R.string.controls_media_button_next), + context.getDrawable(R.drawable.qs_media_round_button_background) ) } else -> null @@ -835,9 +840,10 @@ class MediaDataManager( val it = state.customActions[index] return MediaAction( - Icon.createWithResource(packageName, it.icon), + Icon.createWithResource(packageName, it.icon).loadDrawable(context), { controller.transportControls.sendCustomAction(it, it.extras) }, - it.name + it.name, + context.getDrawable(R.drawable.ic_media_pause_container) ) } @@ -900,9 +906,11 @@ class MediaDataManager( private fun getResumeMediaAction(action: Runnable): MediaAction { return MediaAction( - Icon.createWithResource(context, R.drawable.ic_media_play).setTint(themeText), + Icon.createWithResource(context, R.drawable.ic_media_play) + .setTint(themeText).loadDrawable(context), action, - context.getString(R.string.controls_media_resume) + context.getString(R.string.controls_media_resume), + context.getDrawable(R.drawable.ic_media_play_container) ) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 4e631046063b..e751d549788c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -92,6 +92,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private float mLastPanelFraction; private float mSquishinessFraction = 1; private boolean mQsDisabled; + private int[] mTemp = new int[2]; private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private final MediaHost mQsMediaHost; @@ -141,6 +142,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca */ private float mFullShadeProgress; + private boolean mOverScrolling; + @Inject public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler, QSTileHost qsTileHost, @@ -498,6 +501,12 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } @Override + public void setOverScrollAmount(int overScrollAmount) { + mOverScrolling = overScrollAmount != 0; + getView().setTranslationY(overScrollAmount); + } + + @Override public int getHeightDiff() { return mQSPanelScrollView.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom(); @@ -515,7 +524,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1); boolean onKeyguard = isKeyguardState(); boolean onKeyguardAndExpanded = onKeyguard && !mShowCollapsedOnKeyguard; - if (!mHeaderAnimating && !headerWillBeAnimating()) { + if (!mHeaderAnimating && !headerWillBeAnimating() && !mOverScrolling) { getView().setTranslationY( onKeyguardAndExpanded ? translationScaleY * mHeader.getHeight() @@ -600,8 +609,11 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } mQSPanelScrollView.setClipBounds(mQsBounds); - mQsMediaHost.getCurrentClipping().set(0, 0, getView().getMeasuredWidth(), - mQSPanelScrollView.getMeasuredHeight() - mQSPanelScrollView.getPaddingBottom()); + mQSPanelScrollView.getLocationOnScreen(mTemp); + int top = mTemp[1]; + mQsMediaHost.getCurrentClipping().set(0, top, getView().getMeasuredWidth(), + top + mQSPanelScrollView.getMeasuredHeight() + - mQSPanelScrollView.getPaddingBottom()); } private void updateMediaPositions() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt new file mode 100644 index 000000000000..de37a38e969e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt @@ -0,0 +1,8 @@ +package com.android.systemui.statusbar + +/** Represents an over scroller for the transition to full shade on lock screen. */ +interface LockScreenShadeOverScroller { + + /** The amount in pixels that the user has dragged to expand the shade. */ + var expansionDragDownAmount: Float +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 310eb4f24652..3620e84de398 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -64,6 +64,8 @@ class LockscreenShadeTransitionController @Inject constructor( private val scrimController: ScrimController, private val depthController: NotificationShadeDepthController, private val context: Context, + private val splitShadeOverScrollerFactory: SplitShadeLockScreenOverScroller.Factory, + private val singleShadeOverScrollerFactory: SingleShadeLockScreenOverScroller.Factory, wakefulnessLifecycle: WakefulnessLifecycle, configurationController: ConfigurationController, falsingManager: FalsingManager, @@ -194,6 +196,27 @@ class LockscreenShadeTransitionController @Inject constructor( */ val touchHelper = DragDownHelper(falsingManager, falsingCollector, this, context) + private val splitShadeOverScroller: SplitShadeLockScreenOverScroller by lazy { + splitShadeOverScrollerFactory.create(qS, nsslController) + } + + private val phoneShadeOverScroller: SingleShadeLockScreenOverScroller by lazy { + singleShadeOverScrollerFactory.create(nsslController) + } + + /** + * [LockScreenShadeOverScroller] property that delegates to either + * [SingleShadeLockScreenOverScroller] or [SplitShadeLockScreenOverScroller]. + * + * There are currently two different implementations, as the over scroll behavior is different + * on single shade and split shade. + * + * On single shade, only notifications are over scrolled, whereas on split shade, everything is + * over scrolled. + */ + private val shadeOverScroller: LockScreenShadeOverScroller + get() = if (useSplitShade) splitShadeOverScroller else phoneShadeOverScroller + init { updateResources() configurationController.addCallback(object : ConfigurationController.ConfigurationListener { @@ -410,7 +433,7 @@ class LockscreenShadeTransitionController @Inject constructor( if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) { val notificationShelfProgress = MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance) - nsslController.setTransitionToFullShadeAmount(field, notificationShelfProgress) + nsslController.setTransitionToFullShadeAmount(notificationShelfProgress) qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance) qS.setTransitionToFullShadeAmount(field, qSDragProgress) @@ -422,6 +445,7 @@ class LockscreenShadeTransitionController @Inject constructor( transitionToShadeAmountScrim(field) transitionToShadeAmountCommon(field) transitionToShadeAmountKeyguard(field) + shadeOverScroller.expansionDragDownAmount = dragDownAmount } } } @@ -470,6 +494,9 @@ class LockscreenShadeTransitionController @Inject constructor( } notificationPanelController .setKeyguardTransitionProgress(keyguardAlpha, keyguardTranslationY) + + val statusBarAlpha = if (useSplitShade) keyguardAlpha else -1f + notificationPanelController.setKeyguardStatusBarAlpha(statusBarAlpha) } private fun setDragDownAmountAnimated( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt new file mode 100644 index 000000000000..575f354c6620 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt @@ -0,0 +1,74 @@ +package com.android.systemui.statusbar + +import android.content.Context +import android.content.res.Configuration +import android.util.MathUtils +import com.android.systemui.R +import com.android.systemui.animation.Interpolators +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.policy.ConfigurationController +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class SingleShadeLockScreenOverScroller +@AssistedInject +constructor( + configurationController: ConfigurationController, + private val context: Context, + private val statusBarStateController: SysuiStatusBarStateController, + @Assisted private val nsslController: NotificationStackScrollLayoutController +) : LockScreenShadeOverScroller { + + private var maxOverScrollAmount = 0 + private var totalDistanceForFullShadeTransition = 0 + + init { + updateResources() + configurationController.addCallback( + object : ConfigurationController.ConfigurationListener { + override fun onConfigChanged(newConfig: Configuration?) { + updateResources() + } + }) + } + + private fun updateResources() { + val resources = context.resources + totalDistanceForFullShadeTransition = + resources.getDimensionPixelSize(R.dimen.lockscreen_shade_qs_transition_distance) + maxOverScrollAmount = + resources.getDimensionPixelSize(R.dimen.lockscreen_shade_max_over_scroll_amount) + } + + override var expansionDragDownAmount: Float = 0f + set(value) { + if (value == field) { + return + } + field = value + overScroll() + } + + private fun overScroll() { + var extraTopInset = 0.0f + if (statusBarStateController.state == StatusBarState.KEYGUARD) { + val viewHeight = nsslController.height + val overallProgress = MathUtils.saturate(expansionDragDownAmount / viewHeight) + val transitionProgress = + Interpolators.getOvershootInterpolation( + overallProgress, + 0.6f, + totalDistanceForFullShadeTransition.toFloat() / viewHeight.toFloat()) + extraTopInset = transitionProgress * maxOverScrollAmount + } + nsslController.setOverScrollAmount(extraTopInset.toInt()) + } + + @AssistedFactory + fun interface Factory { + fun create( + nsslController: NotificationStackScrollLayoutController + ): SingleShadeLockScreenOverScroller + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt new file mode 100644 index 000000000000..96ce6b45dc71 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt @@ -0,0 +1,129 @@ +package com.android.systemui.statusbar + +import android.animation.Animator +import android.animation.ValueAnimator +import android.content.Context +import android.content.res.Configuration +import android.util.MathUtils +import android.view.animation.PathInterpolator +import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.R +import com.android.systemui.animation.Interpolators +import com.android.systemui.plugins.qs.QS +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.phone.ScrimController +import com.android.systemui.statusbar.policy.ConfigurationController +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class SplitShadeLockScreenOverScroller +@AssistedInject +constructor( + configurationController: ConfigurationController, + private val context: Context, + private val scrimController: ScrimController, + private val statusBarStateController: SysuiStatusBarStateController, + @Assisted private val qS: QS, + @Assisted private val nsslController: NotificationStackScrollLayoutController +) : LockScreenShadeOverScroller { + + private var releaseOverScrollAnimator: Animator? = null + private var transitionToFullShadeDistance = 0 + private var releaseOverScrollDuration = 0L + private var maxOverScrollAmount = 0 + private var previousOverscrollAmount = 0 + + init { + updateResources() + configurationController.addCallback( + object : ConfigurationController.ConfigurationListener { + override fun onConfigChanged(newConfig: Configuration?) { + updateResources() + } + }) + } + + private fun updateResources() { + val resources = context.resources + transitionToFullShadeDistance = + resources.getDimensionPixelSize(R.dimen.lockscreen_shade_full_transition_distance) + maxOverScrollAmount = + resources.getDimensionPixelSize(R.dimen.lockscreen_shade_max_over_scroll_amount) + releaseOverScrollDuration = + resources.getInteger(R.integer.lockscreen_shade_over_scroll_release_duration).toLong() + } + + override var expansionDragDownAmount: Float = 0f + set(dragDownAmount) { + if (field == dragDownAmount) { + return + } + field = dragDownAmount + if (shouldOverscroll()) { + overScroll(dragDownAmount) + } else if (shouldReleaseOverscroll()) { + releaseOverScroll() + } + } + + private fun shouldOverscroll() = statusBarStateController.state == StatusBarState.KEYGUARD + + private fun shouldReleaseOverscroll() = !shouldOverscroll() && previousOverscrollAmount != 0 + + private fun overScroll(dragDownAmount: Float) { + val overscrollAmount: Int = calculateOverscrollAmount(dragDownAmount) + applyOverscroll(overscrollAmount) + previousOverscrollAmount = overscrollAmount + } + + private fun applyOverscroll(overscrollAmount: Int) { + qS.setOverScrollAmount(overscrollAmount) + scrimController.setNotificationsOverScrollAmount(overscrollAmount) + nsslController.setOverScrollAmount(overscrollAmount) + } + + private fun calculateOverscrollAmount(dragDownAmount: Float): Int { + val fullHeight: Int = nsslController.height + val fullHeightProgress: Float = MathUtils.saturate(dragDownAmount / fullHeight) + val overshootStart: Float = transitionToFullShadeDistance / fullHeight.toFloat() + val overShootTransitionProgress: Float = + Interpolators.getOvershootInterpolation( + fullHeightProgress, OVER_SHOOT_AMOUNT, overshootStart) + return (overShootTransitionProgress * maxOverScrollAmount).toInt() + } + + private fun releaseOverScroll() { + val animator = ValueAnimator.ofInt(previousOverscrollAmount, 0) + animator.addUpdateListener { + val overScrollAmount = it.animatedValue as Int + qS.setOverScrollAmount(overScrollAmount) + scrimController.setNotificationsOverScrollAmount(overScrollAmount) + nsslController.setOverScrollAmount(overScrollAmount) + } + animator.interpolator = RELEASE_OVER_SCROLL_INTERPOLATOR + animator.duration = releaseOverScrollDuration + animator.start() + releaseOverScrollAnimator = animator + previousOverscrollAmount = 0 + } + + @VisibleForTesting + internal fun finishAnimations() { + releaseOverScrollAnimator?.end() + releaseOverScrollAnimator = null + } + + @AssistedFactory + fun interface Factory { + fun create( + qS: QS, + nsslController: NotificationStackScrollLayoutController + ): SplitShadeLockScreenOverScroller + } + + companion object { + private const val OVER_SHOOT_AMOUNT = 0.6f + private val RELEASE_OVER_SCROLL_INTERPOLATOR = PathInterpolator(0.17f, 0f, 0f, 1f) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java index 2baa0797b41f..477db3fb2e3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java @@ -641,28 +641,37 @@ public class ShadeListBuilder implements Dumpable { * Returns true if the group change was suppressed, else false */ private boolean maybeSuppressGroupChange(NotificationEntry entry, List<ListEntry> out) { - if (!entry.wasAttachedInPreviousPass()) { - return false; // new entries are allowed - } - final GroupEntry prevParent = entry.getPreviousAttachState().getParent(); + if (prevParent == null) { + // New entries are always allowed. + return false; + } final GroupEntry assignedParent = entry.getParent(); - if (prevParent != assignedParent - && !getStabilityManager().isGroupChangeAllowed(entry.getRepresentativeEntry())) { + if (prevParent == assignedParent) { + // Nothing to change. + return false; + } + if (prevParent != ROOT_ENTRY && prevParent.getParent() == null) { + // Previous parent was a group, which has been removed (hence, its parent is null). + // Always allow this group change, otherwise the child will remain attached to the + // removed group and be removed from the shade until visual stability ends. + return false; + } + // TODO: Rather than perform "half" of the move here and require the caller remove the child + // from the assignedParent, ideally we would have an atomic "move" operation. + if (!getStabilityManager().isGroupChangeAllowed(entry.getRepresentativeEntry())) { entry.getAttachState().getSuppressedChanges().setParent(assignedParent); entry.setParent(prevParent); if (prevParent == ROOT_ENTRY) { out.add(entry); - } else if (prevParent != null) { + } else { prevParent.addChild(entry); if (!mGroups.containsKey(prevParent.getKey())) { mGroups.put(prevParent.getKey(), prevParent); } } - return true; } - return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt index ff0e47f3cfec..e436ccfd66c6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt @@ -77,6 +77,8 @@ private class KeyguardNotificationVisibilityProviderImpl @Inject constructor( private val secureSettings: SecureSettings, private val globalSettings: GlobalSettings ) : CoreStartable(context), KeyguardNotificationVisibilityProvider { + private val showSilentNotifsUri = + secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS) private val onStateChangedListeners = ListenerSet<Consumer<String>>() private var hideSilentNotificationsOnLockscreen: Boolean = false @@ -100,6 +102,9 @@ private class KeyguardNotificationVisibilityProviderImpl @Inject constructor( // register lockscreen settings changed callbacks: val settingsObserver: ContentObserver = object : ContentObserver(handler) { override fun onChange(selfChange: Boolean, uri: Uri?) { + if (uri == showSilentNotifsUri) { + readShowSilentNotificationSetting() + } if (keyguardStateController.isShowing) { notifyStateChanged("Settings $uri changed") } @@ -152,62 +157,50 @@ private class KeyguardNotificationVisibilityProviderImpl @Inject constructor( onStateChangedListeners.forEach { it.accept(reason) } } - override fun shouldHideNotification(entry: NotificationEntry): Boolean { - val sbn = entry.sbn - // FILTER OUT the notification when the keyguard is showing and... - if (keyguardStateController.isShowing) { - // ... user settings or the device policy manager doesn't allow lockscreen - // notifications; - if (!lockscreenUserManager.shouldShowLockscreenNotifications()) { - return true - } - val currUserId: Int = lockscreenUserManager.currentUserId - val notifUserId = - if (sbn.user.identifier == UserHandle.USER_ALL) currUserId - else sbn.user.identifier - - // ... user is in lockdown - if (keyguardUpdateMonitor.isUserInLockdown(currUserId) || - keyguardUpdateMonitor.isUserInLockdown(notifUserId)) { - return true - } - - // ... device is in public mode and the user's settings doesn't allow - // notifications to show in public mode - if (lockscreenUserManager.isLockscreenPublicMode(currUserId) || - lockscreenUserManager.isLockscreenPublicMode(notifUserId)) { - if (entry.ranking.lockscreenVisibilityOverride == Notification.VISIBILITY_SECRET) { - return true - } - if (!lockscreenUserManager.userAllowsNotificationsInPublic(currUserId) || - !lockscreenUserManager.userAllowsNotificationsInPublic( - notifUserId)) { - return true - } - } + override fun shouldHideNotification(entry: NotificationEntry): Boolean = when { + // Keyguard state doesn't matter if the keyguard is not showing. + !keyguardStateController.isShowing -> false + // Notifications not allowed on the lockscreen, always hide. + !lockscreenUserManager.shouldShowLockscreenNotifications() -> true + // User settings do not allow this notification on the lockscreen, so hide it. + userSettingsDisallowNotification(entry) -> true + // Parent priority is high enough to be shown on the lockscreen, do not hide. + entry.parent?.let(::priorityExceedsLockscreenShowingThreshold) == true -> false + // Entry priority is high enough to be shown on the lockscreen, do not hide. + priorityExceedsLockscreenShowingThreshold(entry) -> false + // Priority is too low, hide. + else -> true + } - // ... neither this notification nor its group have high enough priority - // to be shown on the lockscreen - if (entry.parent != null) { - val parent = entry.parent - if (priorityExceedsLockscreenShowingThreshold(parent)) { - return false - } - } - return !priorityExceedsLockscreenShowingThreshold(entry) + private fun userSettingsDisallowNotification(entry: NotificationEntry): Boolean { + fun disallowForUser(user: Int) = when { + // user is in lockdown, always disallow + keyguardUpdateMonitor.isUserInLockdown(user) -> true + // device isn't public, no need to check public-related settings, so allow + !lockscreenUserManager.isLockscreenPublicMode(user) -> false + // entry is meant to be secret on the lockscreen, disallow + entry.ranking.lockscreenVisibilityOverride == Notification.VISIBILITY_SECRET -> true + // disallow if user disallows notifications in public + else -> !lockscreenUserManager.userAllowsNotificationsInPublic(user) + } + val currentUser = lockscreenUserManager.currentUserId + val notifUser = entry.sbn.user.identifier + return when { + disallowForUser(currentUser) -> true + notifUser == UserHandle.USER_ALL -> false + notifUser == currentUser -> false + else -> disallowForUser(notifUser) } - return false } - private fun priorityExceedsLockscreenShowingThreshold(entry: ListEntry?): Boolean = - when { - entry == null -> false - hideSilentNotificationsOnLockscreen -> highPriorityProvider.isHighPriority(entry) - else -> entry.representativeEntry?.ranking?.isAmbient == false - } + private fun priorityExceedsLockscreenShowingThreshold(entry: ListEntry): Boolean = when { + hideSilentNotificationsOnLockscreen -> highPriorityProvider.isHighPriority(entry) + else -> entry.representativeEntry?.ranking?.isAmbient == false + } private fun readShowSilentNotificationSetting() { - hideSilentNotificationsOnLockscreen = + val showSilentNotifs = secureSettings.getBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true) + hideSilentNotificationsOnLockscreen = !showSilentNotifs } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 3e6f94c67e21..32d37d18f407 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -5026,6 +5026,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable .append(" qsExpandFraction=").append(mQsExpansionFraction) .append(" isCurrentUserSetup=").append(mIsCurrentUserSetup) .append(" hideAmount=").append(mAmbientState.getHideAmount()) + .append(" ambientStateSwipingUp=").append(mAmbientState.isSwipingUp()) .append("]"); pw.println(sb.toString()); DumpUtilsKt.withIncreasedIndent(pw, () -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index d98f8a77cc8d..5bc50ae11fb7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -41,7 +41,6 @@ import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.Log; -import android.util.MathUtils; import android.util.Pair; import android.view.Display; import android.view.LayoutInflater; @@ -65,7 +64,6 @@ import com.android.systemui.ExpandHelper; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.SwipeHelper; -import com.android.systemui.animation.Interpolators; import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -205,18 +203,6 @@ public class NotificationStackScrollLayoutController { private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener; - /** - * The total distance in pixels that the full shade transition takes to transition entirely to - * the full shade. - */ - private int mTotalDistanceForFullShadeTransition; - - /** - * The amount of movement the notifications do when transitioning to the full shade before - * reaching the overstrech - */ - private int mNotificationDragDownMovement; - @VisibleForTesting final View.OnAttachStateChangeListener mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { @@ -304,10 +290,6 @@ public class NotificationStackScrollLayoutController { private NotifStats mNotifStats = NotifStats.getEmpty(); private void updateResources() { - mNotificationDragDownMovement = mResources.getDimensionPixelSize( - R.dimen.lockscreen_shade_notification_movement); - mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize( - R.dimen.lockscreen_shade_qs_transition_distance); mNotificationStackSizeCalculator.updateResources(); } @@ -1537,8 +1519,6 @@ public class NotificationStackScrollLayoutController { } /** - * @param amount The amount of pixels we have currently dragged down - * for the lockscreen to shade transition. 0f for all other states. * @param fraction The fraction of lockscreen to shade transition. * 0f for all other states. * @@ -1546,18 +1526,15 @@ public class NotificationStackScrollLayoutController { * LockscreenShadeTransitionController resets amount and fraction to 0, where they remain * until the next lockscreen-to-shade transition. */ - public void setTransitionToFullShadeAmount(float amount, float fraction) { + public void setTransitionToFullShadeAmount(float fraction) { mView.setFractionToShade(fraction); + } - float extraTopInset = 0.0f; - if (mStatusBarStateController.getState() == KEYGUARD) { - float overallProgress = MathUtils.saturate(amount / mView.getHeight()); - float transitionProgress = Interpolators.getOvershootInterpolation(overallProgress, - 0.6f, - (float) mTotalDistanceForFullShadeTransition / (float) mView.getHeight()); - extraTopInset = transitionProgress * mNotificationDragDownMovement; - } - mView.setExtraTopInsetForFullShadeTransition(extraTopInset); + /** + * Sets the amount of vertical over scroll that should be performed on NSSL. + */ + public void setOverScrollAmount(int overScrollAmount) { + mView.setExtraTopInsetForFullShadeTransition(overScrollAmount); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index c2c8bd3fad5e..1932680de2fa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -641,6 +641,7 @@ public class CentralSurfaces extends CoreStartable implements private boolean mWallpaperSupported; private Runnable mLaunchTransitionEndRunnable; + private Runnable mLaunchTransitionCancelRunnable; private boolean mLaunchCameraWhenFinishedWaking; private boolean mLaunchCameraOnFinishedGoingToSleep; private boolean mLaunchEmergencyActionWhenFinishedWaking; @@ -2967,12 +2968,15 @@ public class CentralSurfaces extends CoreStartable implements * * @param beforeFading the runnable to be run when the circle is fully expanded and the fading * starts - * @param endRunnable the runnable to be run when the transition is done + * @param endRunnable the runnable to be run when the transition is done. Will not run + * if the transition is cancelled, instead cancelRunnable will run + * @param cancelRunnable the runnable to be run if the transition is cancelled */ public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading, - Runnable endRunnable) { + Runnable endRunnable, Runnable cancelRunnable) { mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT); mLaunchTransitionEndRunnable = endRunnable; + mLaunchTransitionCancelRunnable = cancelRunnable; Runnable hideRunnable = () -> { mKeyguardStateController.setLaunchTransitionFadingAway(true); if (beforeFading != null) { @@ -2994,6 +2998,15 @@ public class CentralSurfaces extends CoreStartable implements } } + private void cancelAfterLaunchTransitionRunnables() { + if (mLaunchTransitionCancelRunnable != null) { + mLaunchTransitionCancelRunnable.run(); + } + mLaunchTransitionEndRunnable = null; + mLaunchTransitionCancelRunnable = null; + mNotificationPanelViewController.setLaunchTransitionEndRunnable(null); + } + /** * Fades the content of the Keyguard while we are dozing and makes it invisible when finished * fading. @@ -3033,6 +3046,7 @@ public class CentralSurfaces extends CoreStartable implements } private void runLaunchTransitionEndRunnable() { + mLaunchTransitionCancelRunnable = null; if (mLaunchTransitionEndRunnable != null) { Runnable r = mLaunchTransitionEndRunnable; @@ -3524,6 +3538,10 @@ public class CentralSurfaces extends CoreStartable implements public void onStartedGoingToSleep() { String tag = "CentralSurfaces#onStartedGoingToSleep"; DejankUtils.startDetectingBlockingIpcs(tag); + + // cancel stale runnables that could put the device in the wrong state + cancelAfterLaunchTransitionRunnables(); + updateRevealEffect(false /* wakingUp */); updateNotificationPanelTouchState(); maybeEscalateHeadsUp(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index a70ba8236e9a..57d63487cf7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -229,6 +229,11 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat private boolean mShowingKeyguardHeadsUp; private StatusBarSystemEventAnimator mSystemEventAnimator; + /** + * The alpha value to be set on the View. If -1, this value is to be ignored. + */ + private float mExplicitAlpha = -1f; + @Inject public KeyguardStatusBarViewController( KeyguardStatusBarView view, @@ -425,9 +430,15 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat float alphaQsExpansion = 1 - Math.min( 1, mNotificationPanelViewStateProvider.getLockscreenShadeDragProgress() * 2); - float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion) - * mKeyguardStatusBarAnimateAlpha - * (1.0f - mKeyguardHeadsUpShowingAmount); + + float newAlpha; + if (mExplicitAlpha != -1) { + newAlpha = mExplicitAlpha; + } else { + newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion) + * mKeyguardStatusBarAnimateAlpha + * (1.0f - mKeyguardHeadsUpShowingAmount); + } boolean hideForBypass = mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace() @@ -510,7 +521,17 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardStatusBarView:"); pw.println(" mBatteryListening: " + mBatteryListening); + pw.println(" mExplicitAlpha: " + mExplicitAlpha); mView.dump(fd, pw, args); } + /** + * Sets the alpha to be set on the view. + * + * @param alpha a value between 0 and 1. -1 if the value is to be reset/ignored. + */ + public void setAlpha(float alpha) { + mExplicitAlpha = alpha; + updateViewState(); + } } 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 ebdd257a9fc5..2d16b52839eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -894,10 +894,17 @@ public class NotificationPanelViewController extends PanelViewController { mDepthController.setBlursDisabledForUnlock(mTracking); if (playingCannedAnimation && !isWakeAndUnlock) { - // Fling the panel away so it's not in the way or the surface behind the + // Hide the panel so it's not in the way or the surface behind the // keyguard, which will be appearing. If we're wake and unlocking, the // lock screen is hidden instantly so should not be flung away. - fling(0f, false, 0.7f, false); + if (isTracking() || isFlinging()) { + // Instant collpase the notification panel since the notification + // panel is already in the middle animating + onTrackingStopped(false); + instantCollapse(); + } else { + fling(0f, false, 0.7f, false); + } } } }); @@ -2675,6 +2682,15 @@ public class NotificationPanelViewController extends PanelViewController { updateClock(); } + /** + * Sets the alpha value to be set on the keyguard status bar. + * + * @param alpha value between 0 and 1. -1 if the value is to be reset. + */ + public void setKeyguardStatusBarAlpha(float alpha) { + mKeyguardStatusBarViewController.setAlpha(alpha); + } + private void trackMovement(MotionEvent event) { if (mQsVelocityTracker != null) mQsVelocityTracker.addMovement(event); } @@ -3203,12 +3219,14 @@ public class NotificationPanelViewController extends PanelViewController { @Override protected void onUnlockHintFinished() { super.onUnlockHintFinished(); + mScrimController.setExpansionAffectsAlpha(true); mNotificationStackScrollLayoutController.setUnlockHintRunning(false); } @Override protected void onUnlockHintStarted() { super.onUnlockHintStarted(); + mScrimController.setExpansionAffectsAlpha(false); mNotificationStackScrollLayoutController.setUnlockHintRunning(true); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java index 101c86f6dac1..787c4c0324d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -36,12 +36,14 @@ import com.android.keyguard.LockIconViewController; import com.android.systemui.R; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dock.DockManager; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.lowlightclock.LowLightClockController; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent; @@ -71,6 +73,8 @@ public class NotificationShadeWindowViewController { private final LockIconViewController mLockIconViewController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final StatusBarWindowStateController mStatusBarWindowStateController; + private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + private final AmbientState mAmbientState; private GestureDetector mGestureDetector; private View mBrightnessMirror; @@ -109,7 +113,9 @@ public class NotificationShadeWindowViewController { LockIconViewController lockIconViewController, Optional<LowLightClockController> lowLightClockController, CentralSurfaces centralSurfaces, - NotificationShadeWindowController controller) { + NotificationShadeWindowController controller, + KeyguardUnlockAnimationController keyguardUnlockAnimationController, + AmbientState ambientState) { mLockscreenShadeTransitionController = transitionController; mFalsingCollector = falsingCollector; mTunerService = tunerService; @@ -126,6 +132,8 @@ public class NotificationShadeWindowViewController { mLowLightClockController = lowLightClockController; mService = centralSurfaces; mNotificationShadeWindowController = controller; + mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; + mAmbientState = ambientState; // This view is not part of the newly inflated expanded status bar. mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container); @@ -203,7 +211,6 @@ public class NotificationShadeWindowViewController { // Reset manual touch dispatch state here but make sure the UP/CANCEL event still // gets // delivered. - if (!isCancel && mService.shouldIgnoreTouch()) { return false; } @@ -219,6 +226,16 @@ public class NotificationShadeWindowViewController { return false; } + if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) { + // If the user was sliding their finger across the lock screen, + // we may have been intercepting the touch and forwarding it to the + // UDFPS affordance via mStatusBarKeyguardViewManager.onTouch (see below). + // If this touch ended up unlocking the device, we want to cancel the touch + // immediately, so we don't cause swipe or expand animations afterwards. + cancelCurrentTouch(); + return true; + } + mFalsingCollector.onTouchEvent(ev); mGestureDetector.onTouchEvent(ev); mStatusBarKeyguardViewManager.onTouch(ev); @@ -430,6 +447,7 @@ public class NotificationShadeWindowViewController { event.recycle(); mTouchCancelled = true; } + mAmbientState.setSwipingUp(false); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 78edc07c8544..9398fcd3fabc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -865,6 +865,10 @@ public abstract class PanelViewController { return mClosing || mIsLaunchAnimationRunning; } + public boolean isFlinging() { + return mIsFlinging; + } + public boolean isTracking() { return mTracking; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 029a7a5fcdd5..7e22510c99af 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -52,6 +52,7 @@ import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.scrim.ScrimView; import com.android.systemui.statusbar.notification.stack.ViewState; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; @@ -195,6 +196,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private final Handler mHandler; private final Executor mMainExecutor; private final ScreenOffAnimationController mScreenOffAnimationController; + private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; private GradientColors mColors; private boolean mNeedsDrawableColorUpdate; @@ -211,6 +213,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private float mPanelExpansionFraction = 1f; // Assume shade is expanded during initialization private float mQsExpansion; private boolean mQsBottomVisible; + private boolean mAnimatingPanelExpansionOnUnlock; // don't animate scrim private boolean mDarkenWhileDragging; private boolean mExpansionAffectsAlpha = true; @@ -255,7 +258,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager, ConfigurationController configurationController, @Main Executor mainExecutor, ScreenOffAnimationController screenOffAnimationController, - PanelExpansionStateManager panelExpansionStateManager) { + PanelExpansionStateManager panelExpansionStateManager, + KeyguardUnlockAnimationController keyguardUnlockAnimationController) { mScrimStateListener = lightBarController::setScrimState; mDefaultScrimAlpha = BUSY_SCRIM_ALPHA; @@ -273,6 +277,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump // to make sure that text on top of it is legible. mDozeParameters = dozeParameters; mDockManager = dockManager; + mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; keyguardStateController.addCallback(new KeyguardStateController.Callback() { @Override public void onKeyguardFadingAwayChanged() { @@ -497,6 +502,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump public void onTrackingStarted() { mTracking = true; mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen(); + if (!mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) { + mAnimatingPanelExpansionOnUnlock = false; + } } public void onExpandingFinished() { @@ -567,13 +575,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } if (mPanelExpansionFraction != panelExpansionFraction) { + if (panelExpansionFraction != 0f + && mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) { + mAnimatingPanelExpansionOnUnlock = true; + } else if (panelExpansionFraction == 0f) { + mAnimatingPanelExpansionOnUnlock = false; + } + mPanelExpansionFraction = panelExpansionFraction; boolean relevantState = (mState == ScrimState.UNLOCKED || mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED || mState == ScrimState.PULSING); - if (!(relevantState && mExpansionAffectsAlpha)) { + if (!(relevantState && mExpansionAffectsAlpha) || mAnimatingPanelExpansionOnUnlock) { return; } applyAndDispatchState(); @@ -630,6 +645,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump } /** + * Sets the amount of vertical over scroll that should be performed on the notifications scrim. + */ + public void setNotificationsOverScrollAmount(int overScrollAmount) { + mNotificationsScrim.setTranslationY(overScrollAmount); + } + + /** * Current state of the QuickSettings when pulling it from the top. * * @param expansionFraction From 0 to 1 where 0 means collapsed and 1 expanded. @@ -721,8 +743,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump if (mState == ScrimState.UNLOCKED) { // Darken scrim as you pull down the shade when unlocked, unless the shade is expanding - // because we're doing the screen off animation. - if (!mScreenOffAnimationController.shouldExpandNotifications()) { + // because we're doing the screen off animation OR the shade is collapsing because + // we're playing the unlock animation + if (!mScreenOffAnimationController.shouldExpandNotifications() + && !mAnimatingPanelExpansionOnUnlock) { float behindFraction = getInterpolatedFraction(); behindFraction = (float) Math.pow(behindFraction, 0.8f); if (mClipsQsScrim) { @@ -794,6 +818,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump mNotificationsTint = ScrimState.KEYGUARD.getNotifTint(); } } + if (mState != ScrimState.UNLOCKED) { + mAnimatingPanelExpansionOnUnlock = false; + } assertAlphasValid(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 23a1087edfd8..b8478855e8ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone; import static android.view.WindowInsets.Type.navigationBars; import static com.android.systemui.plugins.ActivityStarter.OnDismissAction; +import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_COLLAPSING; import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING; import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK; import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; @@ -360,7 +361,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } else if (bouncerNeedsScrimming()) { mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE); } else if (mShowing) { - if (!isWakeAndUnlocking() && !mCentralSurfaces.isInLaunchTransition()) { + if (!isWakeAndUnlocking() + && !mCentralSurfaces.isInLaunchTransition() + && !isUnlockCollapsing()) { mBouncer.setExpansion(fraction); } if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking @@ -528,6 +531,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING; } + private boolean isUnlockCollapsing() { + int mode = mBiometricUnlockController.getMode(); + return mode == MODE_UNLOCK_COLLAPSING; + } + /** * Adds a {@param runnable} to be executed after Keyguard is gone. */ @@ -657,14 +665,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb SysUiStatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); if (mCentralSurfaces.isInLaunchTransition()) { setOccludedAndUpdateStates(true); - mCentralSurfaces.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, - new Runnable() { - @Override - public void run() { - mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); - reset(true /* hideBouncerWhenShowing */); - } - }); + final Runnable endRunnable = new Runnable() { + @Override + public void run() { + mNotificationShadeWindowController.setKeyguardOccluded(mOccluded); + reset(true /* hideBouncerWhenShowing */); + } + }; + mCentralSurfaces.fadeKeyguardAfterLaunchTransition( + null /* beforeFading */, + endRunnable, + endRunnable); return; } @@ -759,7 +770,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb hideBouncer(true /* destroyView */); updateStates(); } - }, new Runnable() { + }, /* endRunnable */ new Runnable() { @Override public void run() { mCentralSurfaces.hideKeyguard(); @@ -772,6 +783,15 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mViewMediatorCallback.keyguardGone(); executeAfterKeyguardGoneAction(); } + }, /* cancelRunnable */ new Runnable() { + @Override + public void run() { + mNotificationShadeWindowController.setKeyguardFadingAway(false); + if (wasFlingingToDismissKeyguard) { + mCentralSurfaces.finishKeyguardFadingAway(); + } + cancelPostAuthActions(); + } }); } else { executeAfterKeyguardGoneAction(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index 978564fc81d0..189dca6c6e03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -207,6 +207,8 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum private void setKeyguardFadingAway(boolean keyguardFadingAway) { if (mKeyguardFadingAway != keyguardFadingAway) { + Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardFadingAway", + keyguardFadingAway ? 1 : 0); mKeyguardFadingAway = keyguardFadingAway; ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks); for (int i = 0; i < callbacks.size(); i++) { @@ -217,7 +219,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum @Override public void notifyKeyguardDoneFading() { - mKeyguardGoingAway = false; + notifyKeyguardGoingAway(false); setKeyguardFadingAway(false); } @@ -318,7 +320,11 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum @Override public void notifyKeyguardGoingAway(boolean keyguardGoingAway) { - mKeyguardGoingAway = keyguardGoingAway; + if (mKeyguardGoingAway != keyguardGoingAway) { + Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardGoingAway", + keyguardGoingAway ? 1 : 0); + mKeyguardGoingAway = keyguardGoingAway; + } } @Override @@ -368,6 +374,8 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum pw.println(" mTrusted: " + mTrusted); pw.println(" mDebugUnlocked: " + mDebugUnlocked); pw.println(" mFaceAuthEnabled: " + mFaceAuthEnabled); + pw.println(" isKeyguardFadingAway: " + isKeyguardFadingAway()); + pw.println(" isKeyguardGoingAway: " + isKeyguardGoingAway()); } private class UpdateMonitorCallback extends KeyguardUpdateMonitorCallback { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index ca5edb5c3fb1..8396639fe0f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -51,6 +51,7 @@ import android.util.SparseBooleanArray; import android.view.View; import android.view.WindowManagerGlobal; import android.widget.BaseAdapter; +import android.widget.Toast; import androidx.annotation.Nullable; @@ -59,6 +60,8 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.LatencyTracker; import com.android.settingslib.RestrictedLockUtilsInternal; +import com.android.settingslib.users.UserCreatingDialog; +import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Dumpable; import com.android.systemui.GuestResumeSessionReceiver; import com.android.systemui.Prefs; @@ -89,6 +92,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import javax.inject.Inject; @@ -482,26 +486,25 @@ public class UserSwitcherController implements Dumpable { @VisibleForTesting void onUserListItemClicked(UserRecord record, DialogShower dialogShower) { - int id; if (record.isGuest && record.info == null) { // No guest user. Create one. - int guestId = createGuest(); - if (guestId == UserHandle.USER_NULL) { - // This may happen if we haven't reloaded the user list yet. - return; - } - mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD); - id = guestId; + createGuestAsync(guestId -> { + // guestId may be USER_NULL if we haven't reloaded the user list yet. + if (guestId != UserHandle.USER_NULL) { + mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD); + onUserListItemClicked(guestId, record, dialogShower); + } + }); } else if (record.isAddUser) { showAddUserDialog(dialogShower); - return; } else if (record.isAddSupervisedUser) { startSupervisedUserActivity(); - return; } else { - id = record.info.id; + onUserListItemClicked(record.info.id, record, dialogShower); } + } + private void onUserListItemClicked(int id, UserRecord record, DialogShower dialogShower) { int currUserId = mUserTracker.getUserId(); if (currUserId == id) { if (record.isGuest) { @@ -509,7 +512,6 @@ public class UserSwitcherController implements Dumpable { } return; } - if (UserManager.isGuestUserEphemeral()) { // If switching from guest, we want to bring up the guest exit dialog instead of switching UserInfo currUserInfo = mUserManager.getUserInfo(currUserId); @@ -760,29 +762,30 @@ public class UserSwitcherController implements Dumpable { return; } - try { - if (targetUserId == UserHandle.USER_NULL) { - // Create a new guest in the foreground, and then immediately switch to it - int newGuestId = createGuest(); + if (targetUserId == UserHandle.USER_NULL) { + // Create a new guest in the foreground, and then immediately switch to it + createGuestAsync(newGuestId -> { if (newGuestId == UserHandle.USER_NULL) { Log.e(TAG, "Could not create new guest, switching back to system user"); switchToUserId(UserHandle.USER_SYSTEM); mUserManager.removeUser(currentUser.id); - WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null); + try { + WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't remove guest because ActivityManager " + + "or WindowManager is dead"); + } return; } switchToUserId(newGuestId); mUserManager.removeUser(currentUser.id); - } else { - if (mGuestUserAutoCreated) { - mGuestIsResetting.set(true); - } - switchToUserId(targetUserId); - mUserManager.removeUser(currentUser.id); + }); + } else { + if (mGuestUserAutoCreated) { + mGuestIsResetting.set(true); } - } catch (RemoteException e) { - Log.e(TAG, "Couldn't remove guest because ActivityManager or WindowManager is dead"); - return; + switchToUserId(targetUserId); + mUserManager.removeUser(currentUser.id); } } @@ -831,6 +834,24 @@ public class UserSwitcherController implements Dumpable { } } + private void createGuestAsync(Consumer<Integer> callback) { + final Dialog guestCreationProgressDialog = + new UserCreatingDialog(mContext, /* isGuest= */true); + guestCreationProgressDialog.show(); + + // userManager.createGuest will block the thread so post is needed for the dialog to show + ThreadUtils.postOnMainThread(() -> { + final int guestId = createGuest(); + guestCreationProgressDialog.dismiss(); + if (guestId == UserHandle.USER_NULL) { + Toast.makeText(mContext, + com.android.settingslib.R.string.add_guest_failed, + Toast.LENGTH_SHORT).show(); + } + callback.accept(guestId); + }); + } + /** * Creates a guest user and return its multi-user user ID. * diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index fb8055199d61..c06b8e67c2f8 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -38,6 +38,7 @@ import android.content.om.FabricatedOverlay; import android.content.om.OverlayIdentifier; import android.content.pm.UserInfo; import android.content.res.Configuration; +import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Color; import android.net.Uri; @@ -53,6 +54,7 @@ import android.util.SparseIntArray; import android.util.TypedValue; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.systemui.CoreStartable; @@ -114,10 +116,12 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { private final boolean mIsMonetEnabled; private final UserTracker mUserTracker; private final DeviceProvisionedController mDeviceProvisionedController; + private final Resources mResources; // Current wallpaper colors associated to a user. private final SparseArray<WallpaperColors> mCurrentColors = new SparseArray<>(); private final WallpaperManager mWallpaperManager; - private ColorScheme mColorScheme; + @VisibleForTesting + protected ColorScheme mColorScheme; // If fabricated overlays were already created for the current theme. private boolean mNeedsOverlayCreation; // Dominant color extracted from wallpaper, NOT the color used on the overlay @@ -344,7 +348,7 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { SecureSettings secureSettings, WallpaperManager wallpaperManager, UserManager userManager, DeviceProvisionedController deviceProvisionedController, UserTracker userTracker, DumpManager dumpManager, FeatureFlags featureFlags, - WakefulnessLifecycle wakefulnessLifecycle) { + @Main Resources resources, WakefulnessLifecycle wakefulnessLifecycle) { super(context); mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET); @@ -358,6 +362,7 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { mSecureSettings = secureSettings; mWallpaperManager = wallpaperManager; mUserTracker = userTracker; + mResources = resources; mWakefulnessLifecycle = wakefulnessLifecycle; dumpManager.registerDumpable(TAG, this); } @@ -466,8 +471,13 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { mMainWallpaperColor = mainColor; if (mIsMonetEnabled) { + mThemeStyle = fetchThemeStyleFromSetting(); mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle); mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle); + if (colorSchemeIsApplied()) { + Log.d(TAG, "Skipping overlay creation. Theme was already: " + mColorScheme); + return; + } mNeedsOverlayCreation = true; if (DEBUG) { Log.d(TAG, "fetched overlays. accent: " + mSecondaryOverlay @@ -493,7 +503,7 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { * Given a color candidate, return an overlay definition. */ protected @Nullable FabricatedOverlay getOverlay(int color, int type, Style style) { - boolean nightMode = (mContext.getResources().getConfiguration().uiMode + boolean nightMode = (mResources.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; mColorScheme = new ColorScheme(color, nightMode, style); @@ -525,6 +535,23 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { return overlay.build(); } + /** + * Checks if the color scheme in mColorScheme matches the current system palettes. + */ + private boolean colorSchemeIsApplied() { + return mResources.getColor( + android.R.color.system_accent1_500, mContext.getTheme()) + == mColorScheme.getAccent1().get(6) + && mResources.getColor(android.R.color.system_accent2_500, mContext.getTheme()) + == mColorScheme.getAccent2().get(6) + && mResources.getColor(android.R.color.system_accent3_500, mContext.getTheme()) + == mColorScheme.getAccent3().get(6) + && mResources.getColor(android.R.color.system_neutral1_500, mContext.getTheme()) + == mColorScheme.getNeutral1().get(6) + && mResources.getColor(android.R.color.system_neutral2_500, mContext.getTheme()) + == mColorScheme.getNeutral2().get(6); + } + private void updateThemeOverlays() { final int currentUser = mUserTracker.getUserId(); final String overlayPackageJson = mSecureSettings.getStringForUser( @@ -532,7 +559,6 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { currentUser); if (DEBUG) Log.d(TAG, "updateThemeOverlays. Setting: " + overlayPackageJson); final Map<String, OverlayIdentifier> categoryToPackage = new ArrayMap<>(); - Style newStyle = mThemeStyle; if (!TextUtils.isEmpty(overlayPackageJson)) { try { JSONObject object = new JSONObject(overlayPackageJson); @@ -543,25 +569,11 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { categoryToPackage.put(category, identifier); } } - - try { - newStyle = Style.valueOf( - object.getString(ThemeOverlayApplier.OVERLAY_CATEGORY_THEME_STYLE)); - } catch (IllegalArgumentException e) { - newStyle = Style.TONAL_SPOT; - } } catch (JSONException e) { Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e); } } - if (mIsMonetEnabled && newStyle != mThemeStyle) { - mThemeStyle = newStyle; - mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle); - mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle); - mNeedsOverlayCreation = true; - } - // Let's generate system overlay if the style picker decided to override it. OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE); if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) { @@ -626,6 +638,24 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable { } } + private Style fetchThemeStyleFromSetting() { + Style style = mThemeStyle; + final String overlayPackageJson = mSecureSettings.getStringForUser( + Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, + mUserTracker.getUserId()); + if (!TextUtils.isEmpty(overlayPackageJson)) { + try { + JSONObject object = new JSONObject(overlayPackageJson); + style = Style.valueOf( + object.getString(ThemeOverlayApplier.OVERLAY_CATEGORY_THEME_STYLE)); + } catch (JSONException | IllegalArgumentException e) { + Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e); + style = Style.TONAL_SPOT; + } + } + return style; + } + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mSystemColors=" + mCurrentColors); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index 6736bfd21740..14c903c86b62 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -34,6 +34,7 @@ import static org.mockito.Mockito.when; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Insets; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.Gravity; @@ -204,10 +205,14 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { mKeyguardSecurityContainer.updatePositionByTouchX( mKeyguardSecurityContainer.getWidth() - 1f); + verify(mGlobalSettings).putInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE, + Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT); verify(mSecurityViewFlipper).setTranslationX( mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth()); mKeyguardSecurityContainer.updatePositionByTouchX(1f); + verify(mGlobalSettings).putInt(Settings.Global.ONE_HANDED_KEYGUARD_SIDE, + Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT); verify(mSecurityViewFlipper).setTranslationX(0.0f); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index ac78626ff126..ec92adb0f48c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -33,6 +33,7 @@ import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -60,11 +61,9 @@ import android.util.Size; import android.view.Display; import android.view.DisplayCutout; import android.view.View; -import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowMetrics; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; @@ -103,7 +102,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { private SecureSettings mSecureSettings; private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private FakeThreadFactory mThreadFactory; - private ArrayList<DecorProvider> mPrivacyDecorProviders; + private ArrayList<DecorProvider> mDecorProviders; @Mock private Display mDisplay; @Mock @@ -198,43 +197,17 @@ public class ScreenDecorationsTest extends SysuiTestCase { reset(mTunerService); } - @NonNull - private int[] getRoundCornerIdsFromOverlayId(@DisplayCutout.BoundsPosition int overlayId) { - switch (overlayId) { - case BOUNDS_POSITION_LEFT: - return new int[] { - R.id.rounded_corner_top_left, - R.id.rounded_corner_top_left }; - case BOUNDS_POSITION_TOP: - return new int[] { - R.id.rounded_corner_top_left, - R.id.rounded_corner_top_right }; - case BOUNDS_POSITION_RIGHT: - return new int[] { - R.id.rounded_corner_top_right, - R.id.rounded_corner_bottom_right }; - case BOUNDS_POSITION_BOTTOM: - return new int[] { - R.id.rounded_corner_bottom_left, - R.id.rounded_corner_bottom_right }; - default: - throw new IllegalArgumentException("unknown overlayId: " + overlayId); - } - } - private void verifyRoundedCornerViewsExist( + private void verifyRoundedCornerViewsVisibility( @DisplayCutout.BoundsPosition final int overlayId, - @View.Visibility final boolean isExist) { + @View.Visibility final int visibility) { final View overlay = mScreenDecorations.mOverlays[overlayId].getRootView(); - for (int id: getRoundCornerIdsFromOverlayId(overlayId)) { - final View view = overlay.findViewById(id); - if (isExist) { - assertNotNull(view); - assertThat(view.getVisibility()).isEqualTo(View.VISIBLE); - } else { - assertNull(view); - } - } + final View left = overlay.findViewById(R.id.left); + final View right = overlay.findViewById(R.id.right); + assertNotNull(left); + assertNotNull(right); + assertThat(left.getVisibility()).isEqualTo(visibility); + assertThat(right.getVisibility()).isEqualTo(visibility); } @Nullable @@ -378,8 +351,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(false, true, false, true); // Rounded corner views shall not exist - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); // Privacy dots shall exist but invisible verifyDotViewsVisibility(View.INVISIBLE); @@ -407,8 +380,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(false, true, false, true); // Rounded corner views shall exist - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); // Privacy dots shall not exist verifyDotViewsNullable(true); @@ -435,8 +408,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(false, true, false, true); // Rounded corner views shall exist - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); // Privacy dots shall exist but invisible verifyDotViewsVisibility(View.INVISIBLE); @@ -476,26 +449,21 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView() - .findViewById(R.id.rounded_corner_top_left); + .findViewById(R.id.left); View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView() - .findViewById(R.id.rounded_corner_top_right); - ViewGroup.LayoutParams leftParams = leftRoundedCorner.getLayoutParams(); - ViewGroup.LayoutParams rightParams = rightRoundedCorner.getLayoutParams(); - assertEquals(leftParams.width, testTopRadius); - assertEquals(leftParams.height, testTopRadius); - assertEquals(rightParams.width, testTopRadius); - assertEquals(rightParams.height, testTopRadius); - + .findViewById(R.id.right); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, new Size(testTopRadius, testTopRadius)); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, new Size(testTopRadius, testTopRadius)); leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView() - .findViewById(R.id.rounded_corner_bottom_left); + .findViewById(R.id.left); rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView() - .findViewById(R.id.rounded_corner_bottom_right); - leftParams = leftRoundedCorner.getLayoutParams(); - rightParams = rightRoundedCorner.getLayoutParams(); - assertEquals(leftParams.width, testBottomRadius); - assertEquals(leftParams.height, testBottomRadius); - assertEquals(rightParams.width, testBottomRadius); - assertEquals(rightParams.height, testBottomRadius); + .findViewById(R.id.right); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, new Size(testBottomRadius, testBottomRadius)); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, new Size(testBottomRadius, testBottomRadius)); } @Test @@ -511,27 +479,31 @@ public class ScreenDecorationsTest extends SysuiTestCase { .when(mScreenDecorations).getCutout(); mScreenDecorations.start(); - View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView() - .findViewById(R.id.rounded_corner_top_left); - View bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView() - .findViewById(R.id.rounded_corner_bottom_left); - ViewGroup.LayoutParams topParams = topRoundedCorner.getLayoutParams(); - ViewGroup.LayoutParams bottomParams = bottomRoundedCorner.getLayoutParams(); - assertEquals(topParams.width, testTopRadius); - assertEquals(topParams.height, testTopRadius); - assertEquals(bottomParams.width, testBottomRadius); - assertEquals(bottomParams.height, testBottomRadius); - - topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView() - .findViewById(R.id.rounded_corner_top_right); - bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView() - .findViewById(R.id.rounded_corner_bottom_right); - topParams = topRoundedCorner.getLayoutParams(); - bottomParams = bottomRoundedCorner.getLayoutParams(); - assertEquals(topParams.width, testTopRadius); - assertEquals(topParams.height, testTopRadius); - assertEquals(bottomParams.width, testBottomRadius); - assertEquals(bottomParams.height, testBottomRadius); + final Size topRadius = new Size(testTopRadius, testTopRadius); + final Size bottomRadius = new Size(testBottomRadius, testBottomRadius); + View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView() + .findViewById(R.id.left); + boolean isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.left); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, isTop ? topRadius : bottomRadius); + + View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView() + .findViewById(R.id.right); + isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.right); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, isTop ? topRadius : bottomRadius); + + leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView() + .findViewById(R.id.left); + isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_RIGHT, R.id.left); + verify(mScreenDecorations, atLeastOnce()) + .setSize(leftRoundedCorner, isTop ? topRadius : bottomRadius); + + rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView() + .findViewById(R.id.right); + isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_RIGHT, R.id.right); + verify(mScreenDecorations, atLeastOnce()) + .setSize(rightRoundedCorner, isTop ? topRadius : bottomRadius); } @Test @@ -551,8 +523,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(false, true, false, true); // Rounded corner views shall exist - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); // Privacy dots shall not exist verifyDotViewsNullable(true); @@ -585,8 +557,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(false, true, false, true); // Rounded corner views shall exist - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); // Privacy dots shall exist but invisible verifyDotViewsVisibility(View.INVISIBLE); @@ -645,10 +617,10 @@ public class ScreenDecorationsTest extends SysuiTestCase { // Top rounded corner views shall exist because of cutout // but be gone because of no rounded corner - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); // Bottom rounded corner views shall exist because of privacy dot // but be gone because of no rounded corner - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); // Privacy dots shall exist but invisible verifyDotViewsVisibility(View.INVISIBLE); @@ -676,7 +648,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { // Left rounded corner views shall exist because of cutout // but be gone because of no rounded corner - verifyRoundedCornerViewsExist(BOUNDS_POSITION_LEFT, false); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_LEFT, View.GONE); // Top privacy dots shall not exist because of no privacy verifyDotViewsNullable(true); @@ -728,8 +700,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(false, true, false, true); // Rounded corner views shall exist - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); // Top privacy dots shall not exist because of no privacy dot verifyDotViewsNullable(true); @@ -756,8 +728,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(false, true, false, true); // Rounded corner views shall exist - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); // Top privacy dots shall exist but invisible verifyDotViewsVisibility(View.INVISIBLE); @@ -887,7 +859,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { verifyOverlaysExistAndAdded(true, false, true, false); // Verify each privacy dot id appears only once - mPrivacyDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> { + mDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> { int findCount = 0; for (OverlayWindow overlay: mScreenDecorations.mOverlays) { if (overlay == null) { @@ -941,8 +913,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { // Both top and bottom windows should be added because of privacy dot, // but their visibility shall be gone because of no rounding. verifyOverlaysExistAndAdded(false, true, false, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); when(mContext.getResources().getBoolean( com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) @@ -953,8 +925,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { // Both top and bottom windows should be added because of privacy dot, // but their visibility shall be gone because of no rounding. verifyOverlaysExistAndAdded(false, true, false, true); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false); - verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); } @Test @@ -1202,14 +1174,14 @@ public class ScreenDecorationsTest extends SysuiTestCase { mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout); - mPrivacyDecorProviders = new ArrayList<>(); + mDecorProviders = new ArrayList<>(); if (privacyDot) { - mPrivacyDecorProviders.add(mPrivacyDotTopLeftDecorProvider); - mPrivacyDecorProviders.add(mPrivacyDotTopRightDecorProvider); - mPrivacyDecorProviders.add(mPrivacyDotBottomLeftDecorProvider); - mPrivacyDecorProviders.add(mPrivacyDotBottomRightDecorProvider); + mDecorProviders.add(mPrivacyDotTopLeftDecorProvider); + mDecorProviders.add(mPrivacyDotTopRightDecorProvider); + mDecorProviders.add(mPrivacyDotBottomLeftDecorProvider); + mDecorProviders.add(mPrivacyDotBottomRightDecorProvider); } - when(mPrivacyDotDecorProviderFactory.getProviders()).thenReturn(mPrivacyDecorProviders); + when(mPrivacyDotDecorProviderFactory.getProviders()).thenReturn(mDecorProviders); when(mPrivacyDotDecorProviderFactory.getHasProviders()).thenReturn(privacyDot); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java index 9418b50ff390..f99b20d47ab8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java @@ -42,6 +42,7 @@ import android.view.View; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import org.junit.After; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -50,7 +51,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -@Ignore @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest @@ -66,6 +66,11 @@ public class AuthBiometricViewTest extends SysuiTestCase { private AuthBiometricView mBiometricView; + @After + public void tearDown() { + destroyDialog(); + } + @Test public void testOnAuthenticationSucceeded_noConfirmationRequired_sendsActionAuthenticated() { initDialog(false /* allowDeviceCredential */, mCallback); @@ -245,6 +250,7 @@ public class AuthBiometricViewTest extends SysuiTestCase { // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle // Create new dialog and restore the previous state into it + destroyDialog(); initDialog(false /* allowDeviceCredential */, mCallback, state, 10000); mBiometricView.mAnimationDurationHideDialog = 10000; mBiometricView.setRequireConfirmation(requireConfirmation); @@ -304,6 +310,12 @@ public class AuthBiometricViewTest extends SysuiTestCase { waitForIdleSync(); } + private void destroyDialog() { + if (mBiometricView != null && mBiometricView.isAttachedToWindow()) { + ViewUtils.detachView(mBiometricView); + } + } + @Override protected void waitForIdleSync() { TestableLooper.get(this).processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index cfac96512582..42c3c7f899fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -82,7 +82,6 @@ import com.android.systemui.util.concurrency.Execution; import com.android.systemui.util.concurrency.FakeExecution; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -100,7 +99,6 @@ import java.util.Random; import javax.inject.Provider; -@Ignore @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt index 5182210b9567..ca74df0a23c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt @@ -19,19 +19,25 @@ package com.android.systemui.decor import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.DisplayCutout +import android.view.LayoutInflater import android.view.Surface import android.view.View +import android.view.ViewGroup import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.eq import org.junit.Assert import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.never +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.anyInt import org.mockito.Mockito.spy -import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever @RunWith(AndroidTestingRunner::class) @RunWithLooper(setAsMainLooper = true) @@ -39,88 +45,62 @@ import org.mockito.Mockito.verify class OverlayWindowTest : SysuiTestCase() { companion object { - private val TEST_DECOR_VIEW_ID_1 = R.id.privacy_dot_top_left_container - private val TEST_DECOR_VIEW_ID_2 = R.id.privacy_dot_bottom_right_container + private val TEST_DECOR_VIEW_ID = R.id.privacy_dot_bottom_right_container + private val TEST_DECOR_LAYOUT_ID = R.layout.privacy_dot_bottom_right } private lateinit var overlay: OverlayWindow - private lateinit var decorProvider1: DecorProvider - private lateinit var decorProvider2: DecorProvider + + @Mock private lateinit var layoutInflater: LayoutInflater + @Mock private lateinit var decorProvider: DecorProvider @Before fun setUp() { - decorProvider1 = spy(PrivacyDotCornerDecorProviderImpl( - viewId = TEST_DECOR_VIEW_ID_1, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_TOP, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_LEFT, - layoutId = R.layout.privacy_dot_top_left)) - decorProvider2 = spy(PrivacyDotCornerDecorProviderImpl( - viewId = TEST_DECOR_VIEW_ID_2, - alignedBound1 = DisplayCutout.BOUNDS_POSITION_BOTTOM, - alignedBound2 = DisplayCutout.BOUNDS_POSITION_RIGHT, - layoutId = R.layout.privacy_dot_bottom_right)) + MockitoAnnotations.initMocks(this) + + layoutInflater = spy(LayoutInflater.from(mContext)) + + overlay = OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_RIGHT) + + whenever(decorProvider.viewId).thenReturn(TEST_DECOR_VIEW_ID) + whenever(decorProvider.inflateView( + eq(layoutInflater), + eq(overlay.rootView), + anyInt()) + ).then { + val layoutInflater = it.getArgument<LayoutInflater>(0) + val parent = it.getArgument<ViewGroup>(1) + layoutInflater.inflate(TEST_DECOR_LAYOUT_ID, parent) + return@then parent.getChildAt(parent.childCount - 1) + } + } - overlay = OverlayWindow(mContext) + @Test + fun testAnyBoundsPositionShallNoExceptionForConstructor() { + OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_LEFT) + OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_TOP) + OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_RIGHT) + OverlayWindow(layoutInflater, DisplayCutout.BOUNDS_POSITION_BOTTOM) } @Test fun testAddProvider() { @Surface.Rotation val rotation = Surface.ROTATION_270 - overlay.addDecorProvider(decorProvider1, rotation) - overlay.addDecorProvider(decorProvider2, rotation) - - verify(decorProvider1, times(1)).inflateView( - mContext, overlay.rootView, rotation) - verify(decorProvider2, times(1)).inflateView( - mContext, overlay.rootView, rotation) - - val view1FoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1) - Assert.assertNotNull(view1FoundFromRootView) - Assert.assertEquals(view1FoundFromRootView, overlay.getView(TEST_DECOR_VIEW_ID_1)) - val view2FoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_2) - Assert.assertNotNull(view2FoundFromRootView) - Assert.assertEquals(view2FoundFromRootView, overlay.getView(TEST_DECOR_VIEW_ID_2)) + overlay.addDecorProvider(decorProvider, rotation) + verify(decorProvider, Mockito.times(1)).inflateView( + eq(layoutInflater), eq(overlay.rootView), eq(rotation)) + val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID) + Assert.assertNotNull(viewFoundFromRootView) + Assert.assertEquals(viewFoundFromRootView, overlay.getView(TEST_DECOR_VIEW_ID)) } @Test fun testRemoveView() { - overlay.addDecorProvider(decorProvider1, Surface.ROTATION_270) - overlay.addDecorProvider(decorProvider2, Surface.ROTATION_270) - overlay.removeView(TEST_DECOR_VIEW_ID_1) - - val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID_1) + @Surface.Rotation val rotation = Surface.ROTATION_270 + overlay.addDecorProvider(decorProvider, rotation) + overlay.removeView(TEST_DECOR_VIEW_ID) + val viewFoundFromRootView = overlay.rootView.findViewById<View>(TEST_DECOR_VIEW_ID) Assert.assertNull(viewFoundFromRootView) - Assert.assertNull(overlay.getView(TEST_DECOR_VIEW_ID_1)) - } - - @Test - fun testOnReloadResAndMeasureWithoutIds() { - overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0) - overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0) - - overlay.onReloadResAndMeasure( - reloadToken = 1, - rotation = Surface.ROTATION_90, - displayUniqueId = null) - verify(decorProvider1, times(1)).onReloadResAndMeasure( - overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, null) - verify(decorProvider2, times(1)).onReloadResAndMeasure( - overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, null) - } - - @Test - fun testOnReloadResAndMeasureWithIds() { - overlay.addDecorProvider(decorProvider1, Surface.ROTATION_0) - overlay.addDecorProvider(decorProvider2, Surface.ROTATION_0) - - overlay.onReloadResAndMeasure( - filterIds = arrayOf(TEST_DECOR_VIEW_ID_2), - reloadToken = 1, - rotation = Surface.ROTATION_90, - displayUniqueId = null) - verify(decorProvider1, never()).onReloadResAndMeasure( - overlay.getView(TEST_DECOR_VIEW_ID_1)!!, 1, Surface.ROTATION_90, null) - verify(decorProvider2, times(1)).onReloadResAndMeasure( - overlay.getView(TEST_DECOR_VIEW_ID_2)!!, 1, Surface.ROTATION_90, null) + Assert.assertNull(overlay.getView(TEST_DECOR_LAYOUT_ID)) } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt index 171b76748d26..bac08176d2eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.decor import android.content.res.Resources import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper import android.view.DisplayCutout import androidx.test.filters.SmallTest import com.android.systemui.R @@ -31,6 +32,7 @@ import org.mockito.Mockito.spy import org.mockito.Mockito.`when` as whenever @RunWith(AndroidTestingRunner::class) +@RunWithLooper(setAsMainLooper = true) @SmallTest class PrivacyDotDecorProviderFactoryTest : SysuiTestCase() { private lateinit var mPrivacyDotDecorProviderFactory: PrivacyDotDecorProviderFactory diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt deleted file mode 100644 index 621bcf69bb03..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.decor - -import android.testing.AndroidTestingRunner -import android.util.Size -import android.view.DisplayCutout -import androidx.test.filters.SmallTest -import com.android.systemui.R -import com.android.systemui.SysuiTestCase -import org.junit.Assert -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.Mockito.spy - -@RunWith(AndroidTestingRunner::class) -@SmallTest -class RoundedCornerDecorProviderFactoryTest : SysuiTestCase() { - - @Mock private lateinit var roundedCornerResDelegate: RoundedCornerResDelegate - private lateinit var roundedCornerDecorProviderFactory: RoundedCornerDecorProviderFactory - - @Before - fun setUp() { - roundedCornerResDelegate = spy(RoundedCornerResDelegate(mContext.resources, null)) - } - - @Test - fun testNoRoundedCorners() { - Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).topRoundedSize - Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).bottomRoundedSize - Mockito.doReturn(false).`when`(roundedCornerResDelegate).isMultipleRadius - - roundedCornerDecorProviderFactory = - RoundedCornerDecorProviderFactory(roundedCornerResDelegate) - - Assert.assertEquals(false, roundedCornerDecorProviderFactory.hasProviders) - Assert.assertEquals(0, roundedCornerDecorProviderFactory.providers.size) - } - - @Test - fun testHasRoundedCornersIfTopWidthLargerThan0() { - Mockito.doReturn(Size(1, 0)).`when`(roundedCornerResDelegate).topRoundedSize - Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).bottomRoundedSize - Mockito.doReturn(false).`when`(roundedCornerResDelegate).isMultipleRadius - - roundedCornerDecorProviderFactory = - RoundedCornerDecorProviderFactory(roundedCornerResDelegate) - - Assert.assertEquals(true, roundedCornerDecorProviderFactory.hasProviders) - roundedCornerDecorProviderFactory.providers.let { providers -> - Assert.assertEquals(2, providers.size) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_top_left) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT)) - }) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_top_right) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT)) - }) - } - } - - @Test - fun testHasRoundedCornersIfBottomWidthLargerThan0() { - Mockito.doReturn(Size(0, 0)).`when`(roundedCornerResDelegate).topRoundedSize - Mockito.doReturn(Size(1, 1)).`when`(roundedCornerResDelegate).bottomRoundedSize - Mockito.doReturn(false).`when`(roundedCornerResDelegate).isMultipleRadius - - roundedCornerDecorProviderFactory = - RoundedCornerDecorProviderFactory(roundedCornerResDelegate) - - Assert.assertEquals(true, roundedCornerDecorProviderFactory.hasProviders) - roundedCornerDecorProviderFactory.providers.let { providers -> - Assert.assertEquals(2, providers.size) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_bottom_left) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT)) - }) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_bottom_right) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT)) - }) - } - } - - @Test - fun test4CornerDecorProvidersInfo() { - Mockito.doReturn(Size(10, 10)).`when`(roundedCornerResDelegate).topRoundedSize - Mockito.doReturn(Size(10, 10)).`when`(roundedCornerResDelegate).bottomRoundedSize - Mockito.doReturn(true).`when`(roundedCornerResDelegate).isMultipleRadius - - roundedCornerDecorProviderFactory = - RoundedCornerDecorProviderFactory(roundedCornerResDelegate) - - Assert.assertEquals(true, roundedCornerDecorProviderFactory.hasProviders) - roundedCornerDecorProviderFactory.providers.let { providers -> - Assert.assertEquals(4, providers.size) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_top_left) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT)) - }) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_top_right) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_TOP) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT)) - }) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_bottom_left) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_LEFT)) - }) - Assert.assertEquals(1, providers.count { - ((it.viewId == R.id.rounded_corner_bottom_right) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_BOTTOM) - and it.alignedBounds.contains(DisplayCutout.BOUNDS_POSITION_RIGHT)) - }) - } - } -}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt index e89ed309a1b6..b536bfdb944e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt @@ -45,7 +45,7 @@ class RoundedCornerResDelegateTest : SysuiTestCase() { } @Test - fun testUpdateDisplayUniqueId() { + fun testReloadAllAndDefaultRadius() { mContext.orCreateTestableResources.addOverrides( mockTypeArray = mockTypedArray, radius = 3, @@ -65,34 +65,7 @@ class RoundedCornerResDelegateTest : SysuiTestCase() { radiusTop = 6, radiusBottom = 0) - roundedCornerResDelegate.updateDisplayUniqueId("test", null) - - assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize) - assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize) - } - - @Test - fun testNotUpdateDisplayUniqueIdButChangeRefreshToken() { - mContext.orCreateTestableResources.addOverrides( - mockTypeArray = mockTypedArray, - radius = 3, - radiusTop = 0, - radiusBottom = 4, - multipleRadius = false) - - roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null) - - assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize) - assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize) - assertEquals(false, roundedCornerResDelegate.isMultipleRadius) - - mContext.orCreateTestableResources.addOverrides( - mockTypeArray = mockTypedArray, - radius = 5, - radiusTop = 6, - radiusBottom = 0) - - roundedCornerResDelegate.updateDisplayUniqueId(null, 1) + roundedCornerResDelegate.reloadAll("test") assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize) assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize) @@ -102,24 +75,18 @@ class RoundedCornerResDelegateTest : SysuiTestCase() { fun testUpdateTuningSizeFactor() { mContext.orCreateTestableResources.addOverrides( mockTypeArray = mockTypedArray, - radius = 1, radiusTop = 0, - radiusBottom = 2, + radiusBottom = 0, multipleRadius = false) roundedCornerResDelegate = RoundedCornerResDelegate(mContext.resources, null) val factor = 5 - roundedCornerResDelegate.updateTuningSizeFactor(factor, 1) + roundedCornerResDelegate.updateTuningSizeFactor(factor) val length = (factor * mContext.resources.displayMetrics.density).toInt() assertEquals(Size(length, length), roundedCornerResDelegate.topRoundedSize) assertEquals(Size(length, length), roundedCornerResDelegate.bottomRoundedSize) - - roundedCornerResDelegate.updateTuningSizeFactor(null, 2) - - assertEquals(Size(1, 1), roundedCornerResDelegate.topRoundedSize) - assertEquals(Size(2, 2), roundedCornerResDelegate.bottomRoundedSize) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java new file mode 100644 index 000000000000..c86122141c8f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dreams; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationListener.NotificationHandler; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase { + @Mock + NotificationListener mNotificationListener; + @Mock + DreamOverlayNotificationCountProvider.Callback mCallback; + @Mock + StatusBarNotification mNotification1; + @Mock + StatusBarNotification mNotification2; + @Mock + NotificationListenerService.RankingMap mRankingMap; + + private DreamOverlayNotificationCountProvider mProvider; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + when(mNotification1.getKey()).thenReturn("key1"); + when(mNotification2.getKey()).thenReturn("key2"); + + final StatusBarNotification[] notifications = {mNotification1}; + when(mNotificationListener.getActiveNotifications()).thenReturn(notifications); + mProvider = new DreamOverlayNotificationCountProvider(mNotificationListener); + mProvider.addCallback(mCallback); + } + + @Test + public void testPostingNotificationCallsCallbackWithNotificationCount() { + final ArgumentCaptor<NotificationHandler> handlerArgumentCaptor = + ArgumentCaptor.forClass(NotificationHandler.class); + verify(mNotificationListener).addNotificationHandler(handlerArgumentCaptor.capture()); + handlerArgumentCaptor.getValue().onNotificationPosted(mNotification2, mRankingMap); + verify(mCallback).onNotificationCountChanged(2); + } + + @Test + public void testRemovingNotificationCallsCallbackWithZeroNotificationCount() { + final ArgumentCaptor<NotificationHandler> handlerArgumentCaptor = + ArgumentCaptor.forClass(NotificationHandler.class); + verify(mNotificationListener).addNotificationHandler(handlerArgumentCaptor.capture()); + handlerArgumentCaptor.getValue().onNotificationRemoved(mNotification1, mRankingMap); + verify(mCallback).onNotificationCountChanged(0); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java index a6921b441f17..4915dedb376e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java @@ -31,15 +31,12 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.provider.Settings; -import android.service.notification.NotificationListenerService; -import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.ZenModeController; @@ -84,13 +81,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { @Mock IndividualSensorPrivacyController mSensorPrivacyController; @Mock - StatusBarNotification mStatusBarNotification; - @Mock - NotificationListenerService.RankingMap mRankingMap; - @Mock - NotificationListener mNotificationListener; - @Mock ZenModeController mZenModeController; + @Mock + DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider; private final Executor mMainExecutor = Runnable::run; @@ -113,7 +106,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { mNextAlarmController, mDateFormatUtil, mSensorPrivacyController, - mNotificationListener, + mDreamOverlayNotificationCountProvider, mZenModeController); } @@ -123,6 +116,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { verify(mNextAlarmController).addCallback(any()); verify(mSensorPrivacyController).addCallback(any()); verify(mZenModeController).addCallback(any()); + verify(mDreamOverlayNotificationCountProvider).addCallback(any()); } @Test @@ -202,17 +196,26 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { @Test public void testOnViewAttachedShowsNotificationsIconWhenNotificationsExist() { - StatusBarNotification[] notifications = { mStatusBarNotification }; - when(mNotificationListener.getActiveNotifications()).thenReturn(notifications); mController.onViewAttached(); + + final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture = + ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class); + verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onNotificationCountChanged(1); + verify(mView).showIcon( eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any()); } @Test public void testOnViewAttachedHidesNotificationsIconWhenNoNotificationsExist() { - when(mNotificationListener.getActiveNotifications()).thenReturn(null); mController.onViewAttached(); + + final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture = + ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class); + verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onNotificationCountChanged(0); + verify(mView).showIcon( eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull()); } @@ -248,6 +251,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { verify(mNextAlarmController).removeCallback(any()); verify(mSensorPrivacyController).removeCallback(any()); verify(mZenModeController).removeCallback(any()); + verify(mDreamOverlayNotificationCountProvider).removeCallback(any()); } @Test @@ -309,13 +313,10 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { public void testNotificationsIconShownWhenNotificationAdded() { mController.onViewAttached(); - StatusBarNotification[] notifications = { mStatusBarNotification }; - when(mNotificationListener.getActiveNotifications()).thenReturn(notifications); - - final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture = - ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class); - verify(mNotificationListener).addNotificationHandler(callbackCapture.capture()); - callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap); + final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture = + ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class); + verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onNotificationCountChanged(1); verify(mView).showIcon( eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any()); @@ -323,15 +324,12 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase { @Test public void testNotificationsIconHiddenWhenLastNotificationRemoved() { - StatusBarNotification[] notifications = { mStatusBarNotification }; - when(mNotificationListener.getActiveNotifications()).thenReturn(notifications) - .thenReturn(null); mController.onViewAttached(); - final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture = - ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class); - verify(mNotificationListener).addNotificationHandler(callbackCapture.capture()); - callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap); + final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture = + ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class); + verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture()); + callbackCapture.getValue().onNotificationCountChanged(0); verify(mView).showIcon( eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java index d1d9ec3af711..35bcfcd39fca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java @@ -18,6 +18,7 @@ package com.android.systemui.dreams.complication; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -414,4 +415,37 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase { assertThat(lp.endToEnd == ConstraintLayout.LayoutParams.PARENT_ID).isTrue(); }); } + + /** + * Ensures a second removal of a complication is a no-op. + */ + @Test + public void testDoubleRemoval() { + final ComplicationLayoutEngine engine = + new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0); + + final ViewInfo firstViewInfo = new ViewInfo( + new ComplicationLayoutParams( + 100, + 100, + ComplicationLayoutParams.POSITION_TOP + | ComplicationLayoutParams.POSITION_END, + ComplicationLayoutParams.DIRECTION_DOWN, + 0), + Complication.CATEGORY_STANDARD, + mLayout); + + engine.addComplication(firstViewInfo.id, firstViewInfo.view, firstViewInfo.lp, + firstViewInfo.category); + verify(mLayout).addView(firstViewInfo.view); + + assertThat(engine.removeComplication(firstViewInfo.id)).isTrue(); + verify(firstViewInfo.view).getParent(); + verify(mLayout).removeView(firstViewInfo.view); + + Mockito.clearInvocations(mLayout, firstViewInfo.view); + assertThat(engine.removeComplication(firstViewInfo.id)).isFalse(); + verify(firstViewInfo.view, never()).getParent(); + verify(mLayout, never()).removeView(firstViewInfo.view); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index d0f2816f3bcd..04609ad25da9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -19,8 +19,9 @@ package com.android.systemui.media import org.mockito.Mockito.`when` as whenever import android.content.Intent import android.graphics.Color +import android.graphics.drawable.Animatable2 +import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.GradientDrawable -import android.graphics.drawable.Icon import android.graphics.drawable.RippleDrawable import android.media.MediaMetadata import android.media.session.MediaSession @@ -60,6 +61,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyLong import org.mockito.Mock +import org.mockito.Mockito.any import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times @@ -290,15 +292,15 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindSemanticActions() { - val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play) + val icon = context.getDrawable(android.R.drawable.ic_media_play) + val bg = context.getDrawable(R.drawable.qs_media_round_button_background) val semanticActions = MediaButton( - playOrPause = MediaAction(icon, Runnable {}, "play"), - nextOrCustom = MediaAction(icon, Runnable {}, "next"), - custom0 = MediaAction(icon, null, "custom 0"), - custom1 = MediaAction(icon, null, "custom 1") + playOrPause = MediaAction(icon, Runnable {}, "play", bg), + nextOrCustom = MediaAction(icon, Runnable {}, "next", bg), + custom0 = MediaAction(icon, null, "custom 0", bg), + custom1 = MediaAction(icon, null, "custom 1", bg) ) val state = mediaData.copy(semanticActions = semanticActions) - player.attachPlayer(viewHolder) player.bindPlayer(state, PACKAGE) @@ -338,10 +340,10 @@ public class MediaControlPanelTest : SysuiTestCase() { fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() { whenever(seekBarViewModel.getEnabled()).thenReturn(false) - val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play) + val icon = context.getDrawable(android.R.drawable.ic_media_play) val semanticActions = MediaButton( - playOrPause = MediaAction(icon, Runnable {}, "play"), - nextOrCustom = MediaAction(icon, Runnable {}, "next") + playOrPause = MediaAction(icon, Runnable {}, "play", null), + nextOrCustom = MediaAction(icon, Runnable {}, "next", null) ) val state = mediaData.copy(semanticActions = semanticActions) @@ -365,13 +367,14 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindNotificationActions() { - val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play) + val icon = context.getDrawable(android.R.drawable.ic_media_play) + val bg = context.getDrawable(R.drawable.qs_media_round_button_background) val actions = listOf( - MediaAction(icon, Runnable {}, "previous"), - MediaAction(icon, Runnable {}, "play"), - MediaAction(icon, null, "next"), - MediaAction(icon, null, "custom 0"), - MediaAction(icon, Runnable {}, "custom 1") + MediaAction(icon, Runnable {}, "previous", bg), + MediaAction(icon, Runnable {}, "play", bg), + MediaAction(icon, null, "next", bg), + MediaAction(icon, null, "custom 0", bg), + MediaAction(icon, Runnable {}, "custom 1", bg) ) val state = mediaData.copy(actions = actions, actionsToShowInCompact = listOf(1, 2), @@ -413,6 +416,72 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun bindAnimatedSemanticActions() { + val mockAvd0 = mock(AnimatedVectorDrawable::class.java) + val mockAvd1 = mock(AnimatedVectorDrawable::class.java) + val mockAvd2 = mock(AnimatedVectorDrawable::class.java) + whenever(mockAvd0.mutate()).thenReturn(mockAvd0) + whenever(mockAvd1.mutate()).thenReturn(mockAvd1) + whenever(mockAvd2.mutate()).thenReturn(mockAvd2) + + val icon = context.getDrawable(R.drawable.ic_media_play) + val bg = context.getDrawable(R.drawable.ic_media_play_container) + val semanticActions0 = MediaButton( + playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null)) + val semanticActions1 = MediaButton( + playOrPause = MediaAction(mockAvd1, Runnable {}, "pause", null)) + val semanticActions2 = MediaButton( + playOrPause = MediaAction(mockAvd2, Runnable {}, "loading", null)) + val state0 = mediaData.copy(semanticActions = semanticActions0) + val state1 = mediaData.copy(semanticActions = semanticActions1) + val state2 = mediaData.copy(semanticActions = semanticActions2) + + player.attachPlayer(viewHolder) + player.bindPlayer(state0, PACKAGE) + + // Validate first binding + assertThat(actionPlayPause.isEnabled()).isTrue() + assertThat(actionPlayPause.contentDescription).isEqualTo("play") + verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.VISIBLE) + assertThat(actionPlayPause.hasOnClickListeners()).isTrue() + + // Trigger animation & update mock + actionPlayPause.performClick() + verify(mockAvd0, times(1)).start() + whenever(mockAvd0.isRunning()).thenReturn(true) + + // Validate states no longer bind + player.bindPlayer(state1, PACKAGE) + player.bindPlayer(state2, PACKAGE) + assertThat(actionPlayPause.contentDescription).isEqualTo("play") + + // Complete animation and run callbacks + whenever(mockAvd0.isRunning()).thenReturn(false) + val captor = ArgumentCaptor.forClass(Animatable2.AnimationCallback::class.java) + verify(mockAvd0, times(1)).registerAnimationCallback(captor.capture()) + verify(mockAvd1, never()) + .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + verify(mockAvd2, never()) + .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + captor.getValue().onAnimationEnd(mockAvd0) + + // Validate correct state was bound + assertThat(actionPlayPause.contentDescription).isEqualTo("loading") + verify(mockAvd0, times(1)) + .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + verify(mockAvd1, times(1) + ).registerAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + verify(mockAvd2, times(1)) + .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + verify(mockAvd0, times(1)) + .unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + verify(mockAvd1, times(1)) + .unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + verify(mockAvd2, never()) + .unregisterAnimationCallback(any(Animatable2.AnimationCallback::class.java)) + } + + @Test fun bindText() { player.attachPlayer(viewHolder) player.bindPlayer(mediaData, PACKAGE) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index 1d2a0ca3777a..fc19d131f351 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -44,6 +44,7 @@ import org.mockito.Mockito import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyZeroInteractions import org.mockito.junit.MockitoJUnit private fun <T> anyObject(): T { @@ -75,6 +76,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Mock lateinit var expandHelperCallback: ExpandHelper.Callback @Mock lateinit var mCentralSurfaces: CentralSurfaces @Mock lateinit var qS: QS + @Mock lateinit var singleShadeOverScroller: SingleShadeLockScreenOverScroller + @Mock lateinit var splitShadeOverScroller: SplitShadeLockScreenOverScroller @JvmField @Rule val mockito = MockitoJUnit.rule() private val configurationController = FakeConfigurationController() @@ -104,7 +107,9 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { context = context, configurationController = configurationController, falsingManager = falsingManager, - dumpManager = dumpManager + dumpManager = dumpManager, + splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller }, + singleShadeOverScrollerFactory = { singleShadeOverScroller } ) whenever(nsslController.view).thenReturn(stackscroller) whenever(nsslController.expandHelperCallback).thenReturn(expandHelperCallback) @@ -229,7 +234,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { fun testDragDownAmountDoesntCallOutInLockedDownShade() { whenever(nsslController.isInLockedDownShade).thenReturn(true) transitionController.dragDownAmount = 10f - verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) + verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat()) verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat()) verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat()) verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(), @@ -240,7 +245,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Test fun testDragDownAmountCallsOut() { transitionController.dragDownAmount = 10f - verify(nsslController).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) + verify(nsslController).setTransitionToFullShadeAmount(anyFloat()) verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat()) verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat()) verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(), @@ -250,14 +255,25 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { } @Test - fun testDragDownAmount_depthDistanceIsZero_doesNotSetProgress() { + fun testDragDownAmount_depthDistanceIsZero_setsProgressToZero() { context.getOrCreateTestableResources() .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 0) configurationController.notifyConfigurationChanged() transitionController.dragDownAmount = 10f - verify(depthController, never()).transitionToFullShadeProgress + verify(depthController).transitionToFullShadeProgress = 0f + } + + @Test + fun testDragDownAmount_depthDistanceNonZero_setsProgressBasedOnDistance() { + context.getOrCreateTestableResources() + .addOverride(R.dimen.lockscreen_shade_depth_controller_transition_distance, 100) + configurationController.notifyConfigurationChanged() + + transitionController.dragDownAmount = 10f + + verify(depthController).transitionToFullShadeProgress = 0.1f } @Test @@ -388,6 +404,48 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f) } + @Test + fun setDragAmount_notInSplitShade_forwardsToSingleShadeOverScroller() { + disableSplitShade() + + transitionController.dragDownAmount = 10f + + verify(singleShadeOverScroller).expansionDragDownAmount = 10f + verifyZeroInteractions(splitShadeOverScroller) + } + + @Test + fun setDragAmount_inSplitShade_forwardsToSplitShadeOverScroller() { + enableSplitShade() + + transitionController.dragDownAmount = 10f + + verify(splitShadeOverScroller).expansionDragDownAmount = 10f + verifyZeroInteractions(singleShadeOverScroller) + } + + @Test + fun setDragDownAmount_inSplitShade_setsKeyguardStatusBarAlphaBasedOnDistance() { + val alphaDistance = context.resources.getDimensionPixelSize( + R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance) + val dragDownAmount = 10f + enableSplitShade() + + transitionController.dragDownAmount = dragDownAmount + + val expectedAlpha = 1 - dragDownAmount / alphaDistance + verify(notificationPanelController).setKeyguardStatusBarAlpha(expectedAlpha) + } + + @Test + fun setDragDownAmount_notInSplitShade_setsKeyguardStatusBarAlphaToMinusOne() { + disableSplitShade() + + transitionController.dragDownAmount = 10f + + verify(notificationPanelController).setKeyguardStatusBarAlpha(-1f) + } + private fun enableSplitShade() { setSplitShadeEnabled(true) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt new file mode 100644 index 000000000000..2606be5fabad --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt @@ -0,0 +1,56 @@ +package com.android.systemui.statusbar + +import org.mockito.Mockito.`when` as whenever +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.policy.FakeConfigurationController +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.intThat +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class SingleShadeLockScreenOverScrollerTest : SysuiTestCase() { + + @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController + @Mock private lateinit var nsslController: NotificationStackScrollLayoutController + + private lateinit var overScroller: SingleShadeLockScreenOverScroller + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(nsslController.height).thenReturn(1800) + overScroller = + SingleShadeLockScreenOverScroller( + FakeConfigurationController(), + context, + statusBarStateController, + nsslController + ) + } + + @Test + fun setDragDownAmount_onKeyguard_overScrolls() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + + overScroller.expansionDragDownAmount = 10f + + verify(nsslController).setOverScrollAmount(intThat { it > 0 }) + } + + @Test + fun setDragDownAmount_notOnKeyguard_doesNotOverScroll() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE) + + overScroller.expansionDragDownAmount = 10f + + verify(nsslController).setOverScrollAmount(0) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt new file mode 100644 index 000000000000..9d5099cfafd0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt @@ -0,0 +1,124 @@ +package com.android.systemui.statusbar + +import org.mockito.Mockito.`when` as whenever +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.qs.QS +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.phone.ScrimController +import com.android.systemui.statusbar.policy.FakeConfigurationController +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.atLeast +import org.mockito.Mockito.intThat +import org.mockito.Mockito.reset +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.verifyZeroInteractions +import org.mockito.MockitoAnnotations + +@RunWith(AndroidTestingRunner::class) +@SmallTest +@TestableLooper.RunWithLooper +class SplitShadeLockScreenOverScrollerTest : SysuiTestCase() { + + private val configurationController = FakeConfigurationController() + + @Mock private lateinit var scrimController: ScrimController + @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController + @Mock private lateinit var qS: QS + @Mock private lateinit var nsslController: NotificationStackScrollLayoutController + + private lateinit var overScroller: SplitShadeLockScreenOverScroller + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + whenever(nsslController.height).thenReturn(1800) + + overScroller = + SplitShadeLockScreenOverScroller( + configurationController, + context, + scrimController, + statusBarStateController, + qS, + nsslController) + } + + @Test + fun setDragDownAmount_onKeyguard_appliesOverScroll() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + + setDragAmount(1000f) + + verifyOverScrollPerformed() + } + + @Test + fun setDragDownAmount_notOnKeyguard_doesNotApplyOverScroll() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE) + + setDragAmount(1000f) + + verifyZeroInteractions(qS) + verifyZeroInteractions(scrimController) + verifyZeroInteractions(nsslController) + } + + @Test + fun setDragAmount_onKeyguard_thenNotOnKeyguard_resetsOverScrollToZero() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + setDragAmount(1000f) + verifyOverScrollPerformed() + reset(qS, scrimController, nsslController) + + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE) + setDragAmount(999f) + verifyOverScrollResetToZero() + } + + @Test + fun setDragAmount_onKeyguard_thenNotOnKeyguard_multipleTimes_resetsOverScrollToZeroOnlyOnce() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + setDragAmount(1000f) + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE) + setDragAmount(999f) + reset(qS, scrimController, nsslController) + + setDragAmount(998f) + setDragAmount(997f) + setDragAmount(996f) + verifyNoMoreOverScrollChanges() + } + + private fun verifyOverScrollPerformed() { + verify(qS).setOverScrollAmount(intThat { it > 0 }) + verify(scrimController).setNotificationsOverScrollAmount(intThat { it > 0 }) + verify(nsslController).setOverScrollAmount(intThat { it > 0 }) + } + + private fun verifyOverScrollResetToZero() { + // Might be more than once as the animator might have multiple values close to zero that + // round down to zero. + verify(qS, atLeast(1)).setOverScrollAmount(0) + verify(scrimController, atLeast(1)).setNotificationsOverScrollAmount(0) + verify(nsslController, atLeast(1)).setOverScrollAmount(0) + } + + private fun verifyNoMoreOverScrollChanges() { + verifyNoMoreInteractions(qS) + verifyNoMoreInteractions(scrimController) + verifyNoMoreInteractions(nsslController) + } + + private fun setDragAmount(dragDownAmount: Float) { + overScroller.expansionDragDownAmount = dragDownAmount + overScroller.finishAnimations() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java index f470715b92c4..dd0c7589d7a1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java @@ -1173,6 +1173,29 @@ public class ShadeListBuilderTest extends SysuiTestCase { } @Test + public void testStabilizeGroupsAlwaysAllowsGroupChangeFromDeletedGroupToRoot() { + // GIVEN a group w/ summary and two children + addGroupSummary(0, PACKAGE_1, GROUP_1); + addGroupChild(1, PACKAGE_1, GROUP_1); + addGroupChild(2, PACKAGE_1, GROUP_1); + dispatchBuild(); + + // GIVEN visual stability manager doesn't allow any group changes + mStabilityManager.setAllowGroupChanges(false); + + // WHEN we run the pipeline with the summary and one child removed + mEntrySet.remove(2); + mEntrySet.remove(0); + dispatchBuild(); + + // THEN all that remains is the one child at top-level, despite no group change allowed by + // visual stability manager. + verifyBuiltList( + notif(0) + ); + } + + @Test public void testStabilizeGroupsDoesNotAllowGroupingExistingNotifications() { // GIVEN one group child without a summary yet addGroupChild(0, PACKAGE_1, GROUP_1); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java index 32d625c707cf..4e07d5924229 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.interruption; import static android.app.Notification.VISIBILITY_PUBLIC; import static android.app.Notification.VISIBILITY_SECRET; import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MIN; import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry; @@ -209,7 +210,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase { Consumer<String> listener = mock(Consumer.class); mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener); - mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1); + mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, true); verify(listener).accept(anyString()); } @@ -220,7 +221,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase { Consumer<String> listener = mock(Consumer.class); mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener); - mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1); + mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, true); verify(listener).accept(anyString()); } @@ -231,7 +232,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase { Consumer<String> listener = mock(Consumer.class); mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener); - mFakeSettings.putInt(Settings.Global.ZEN_MODE, 1); + mFakeSettings.putBool(Settings.Global.ZEN_MODE, true); verify(listener).accept(anyString()); } @@ -242,7 +243,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase { Consumer<String> listener = mock(Consumer.class); mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener); - mFakeSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1); + mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true); verify(listener).accept(anyString()); } @@ -338,6 +339,25 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase { } @Test + public void showSilentOnLockscreenSetting() { + // GIVEN an 'unfiltered-keyguard-showing' state + setupUnfilteredState(mEntry); + + // WHEN the notification is not high priority and not ambient + mEntry.setRanking(new RankingBuilder() + .setKey(mEntry.getKey()) + .setImportance(IMPORTANCE_LOW) + .build()); + when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false); + + // WHEN the show silent notifs on lockscreen setting is true + mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, true); + + // THEN do not filter out the entry + assertFalse(mKeyguardNotificationVisibilityProvider.shouldHideNotification(mEntry)); + } + + @Test public void summaryExceedsThresholdToShow() { // GIVEN the notification doesn't exceed the threshold to show on the lockscreen // but it's part of a group (has a parent) @@ -360,6 +380,7 @@ public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase { .build()); // WHEN its parent does exceed threshold tot show on the lockscreen + mFakeSettings.putBool(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, false); when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true); // THEN don't filter out the entry diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index 7de35458a893..39d5a160c657 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -343,6 +343,28 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase { assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE); } + @Test + public void setAlpha_explicitAlpha_setsExplicitAlpha() { + mController.onViewAttached(); + updateStateToKeyguard(); + + mController.setAlpha(0.5f); + + assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(0.5f); + } + + @Test + public void setAlpha_explicitAlpha_thenMinusOneAlpha_setsAlphaBasedOnDefaultCriteria() { + mController.onViewAttached(); + updateStateToKeyguard(); + + mController.setAlpha(0.5f); + mController.setAlpha(-1f); + + assertThat(mKeyguardStatusBarView.getAlpha()).isGreaterThan(0); + assertThat(mKeyguardStatusBarView.getAlpha()).isNotEqualTo(0.5f); + } + // TODO(b/195442899): Add more tests for #updateViewState once CLs are finalized. @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 21d03adb64ef..22bf6c8324ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -930,6 +930,23 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { verify(mLargeScreenShadeHeaderController).setActive(false); } + @Test + public void testUnlockAnimationDoesNotAffectScrim() { + mNotificationPanelViewController.onUnlockHintStarted(); + verify(mScrimController).setExpansionAffectsAlpha(false); + mNotificationPanelViewController.onUnlockHintFinished(); + verify(mScrimController).setExpansionAffectsAlpha(true); + } + + @Test + public void setKeyguardStatusBarAlpha_setsAlphaOnKeyguardStatusBarController() { + float statusBarAlpha = 0.5f; + + mNotificationPanelViewController.setKeyguardStatusBarAlpha(statusBarAlpha); + + verify(mKeyguardStatusBarViewController).setAlpha(statusBarAlpha); + } + private void triggerPositionClockAndNotifications() { mNotificationPanelViewController.closeQs(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt index 093f92646115..7e245fcea22d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt @@ -24,11 +24,13 @@ import com.android.keyguard.LockIconViewController import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.dock.DockManager +import com.android.systemui.keyguard.KeyguardUnlockAnimationController import com.android.systemui.lowlightclock.LowLightClockController import com.android.systemui.statusbar.LockscreenShadeTransitionController import com.android.systemui.statusbar.NotificationShadeDepthController import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.stack.AmbientState import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.phone.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager @@ -71,6 +73,10 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock private lateinit var mNotificationShadeWindowController: NotificationShadeWindowController @Mock + private lateinit var mKeyguardUnlockAnimationController: KeyguardUnlockAnimationController + @Mock + private lateinit var mAmbientState: AmbientState + @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController @Mock private lateinit var mStatusBarKeyguardViewManager: StatusBarKeyguardViewManager @@ -109,7 +115,9 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { mLockIconViewController, Optional.of(mLowLightClockController), mCentralSurfaces, - mNotificationShadeWindowController + mNotificationShadeWindowController, + mKeyguardUnlockAnimationController, + mAmbientState ) mController.setupExpandedStatusBar() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index 62a1bcdc0184..1d86fb13a1f6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java @@ -37,12 +37,14 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.dock.DockManager; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.lowlightclock.LowLightClockController; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; @@ -83,6 +85,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController; @Mock private LockIconViewController mLockIconViewController; @Mock private LowLightClockController mLowLightClockController; + @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; + @Mock private AmbientState mAmbientState; @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler> mInteractionEventHandlerCaptor; @@ -117,7 +121,9 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mLockIconViewController, Optional.of(mLowLightClockController), mCentralSurfaces, - mNotificationShadeWindowController); + mNotificationShadeWindowController, + mKeyguardUnlockAnimationController, + mAmbientState); mController.setupExpandedStatusBar(); mController.setDragDownHelper(mDragDownHelper); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 786a8586ea39..134ad4b9d0fb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -53,6 +53,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; +import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.scrim.ScrimView; import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -112,6 +113,8 @@ public class ScrimControllerTest extends SysuiTestCase { private ConfigurationController mConfigurationController; @Mock private ScreenOffAnimationController mScreenOffAnimationController; + @Mock + private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // event-dispatch-on-registration pattern caused some of these unit tests to fail.) @Mock @@ -229,7 +232,8 @@ public class ScrimControllerTest extends SysuiTestCase { new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mDockManager, mConfigurationController, new FakeExecutor(new FakeSystemClock()), mScreenOffAnimationController, - mPanelExpansionStateManager); + mPanelExpansionStateManager, + mKeyguardUnlockAnimationController); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront); mScrimController.setAnimatorListener(mAnimatorListener); @@ -1292,6 +1296,33 @@ public class ScrimControllerTest extends SysuiTestCase { assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress); } + @Test + public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() { + int overScrollAmount = 10; + + mScrimController.setNotificationsOverScrollAmount(overScrollAmount); + + assertThat(mNotificationsScrim.getTranslationY()).isEqualTo(overScrollAmount); + } + + @Test + public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnBehindScrim() { + int overScrollAmount = 10; + + mScrimController.setNotificationsOverScrollAmount(overScrollAmount); + + assertThat(mScrimBehind.getTranslationY()).isEqualTo(0); + } + + @Test + public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnFrontScrim() { + int overScrollAmount = 10; + + mScrimController.setNotificationsOverScrollAmount(overScrollAmount); + + assertThat(mScrimInFront.getTranslationY()).isEqualTo(0); + } + private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) { mScrimController.setRawPanelExpansionFraction(expansion); finishAnimationsImmediately(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java index 7c05c69ff3b5..6c83e9f88d63 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java @@ -57,33 +57,33 @@ public class SystemUIDialogTest extends SysuiTestCase { @Test public void testRegisterReceiver() { - final SystemUIDialog mDialog = new SystemUIDialog(mContext); + final SystemUIDialog dialog = new SystemUIDialog(mContext); final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); final ArgumentCaptor<IntentFilter> intentFilterCaptor = ArgumentCaptor.forClass(IntentFilter.class); - mDialog.show(); + dialog.show(); verify(mBroadcastDispatcher).registerReceiver(broadcastReceiverCaptor.capture(), intentFilterCaptor.capture(), eq(null), any()); assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_SCREEN_OFF)); assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - mDialog.dismiss(); + dialog.dismiss(); verify(mBroadcastDispatcher).unregisterReceiver(eq(broadcastReceiverCaptor.getValue())); } @Test public void testNoRegisterReceiver() { - final SystemUIDialog mDialog = new SystemUIDialog(mContext, false); + final SystemUIDialog dialog = new SystemUIDialog(mContext, false); - mDialog.show(); + dialog.show(); verify(mBroadcastDispatcher, never()).registerReceiver(any(), any(), eq(null), any()); - assertTrue(mDialog.isShowing()); + assertTrue(dialog.isShowing()); - mDialog.dismiss(); + dialog.dismiss(); verify(mBroadcastDispatcher, never()).unregisterReceiver(any()); - assertFalse(mDialog.isShowing()); + assertFalse(dialog.isShowing()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index f804d83a66a6..b8f66fc41f04 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -39,6 +39,7 @@ import android.content.BroadcastReceiver; import android.content.Intent; import android.content.om.FabricatedOverlay; import android.content.om.OverlayIdentifier; +import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Color; import android.os.Handler; @@ -56,6 +57,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.monet.ColorScheme; import com.android.systemui.monet.Style; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -108,6 +110,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { @Mock private FeatureFlags mFeatureFlags; @Mock + private Resources mResources; + @Mock private WakefulnessLifecycle mWakefulnessLifecycle; @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver; @@ -129,10 +133,20 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true); when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE); when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); - mThemeOverlayController = new ThemeOverlayController(null /* context */, + when(mResources.getColor(eq(android.R.color.system_accent1_500), any())) + .thenReturn(Color.RED); + when(mResources.getColor(eq(android.R.color.system_accent2_500), any())) + .thenReturn(Color.GREEN); + when(mResources.getColor(eq(android.R.color.system_accent3_500), any())) + .thenReturn(Color.BLUE); + when(mResources.getColor(eq(android.R.color.system_neutral1_500), any())) + .thenReturn(Color.YELLOW); + when(mResources.getColor(eq(android.R.color.system_neutral2_500), any())) + .thenReturn(Color.BLACK); + mThemeOverlayController = new ThemeOverlayController(mContext, mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, - mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) { + mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) { @Nullable @Override protected FabricatedOverlay getOverlay(int color, int type, Style style) { @@ -140,6 +154,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { when(overlay.getIdentifier()) .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000))); mCurrentStyle = style; + mColorScheme = new ColorScheme(color, false /* nightMode */, style); return overlay; } }; @@ -643,16 +658,17 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { Executor executor = MoreExecutors.directExecutor(); - mThemeOverlayController = new ThemeOverlayController(null /* context */, + mThemeOverlayController = new ThemeOverlayController(mContext, mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, - mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) { + mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) { @Nullable @Override protected FabricatedOverlay getOverlay(int color, int type, Style style) { FabricatedOverlay overlay = mock(FabricatedOverlay.class); when(overlay.getIdentifier()) .thenReturn(new OverlayIdentifier("com.thebest.livewallpaperapp.ever")); + mColorScheme = new ColorScheme(color, false /* nightMode */, style); return overlay; } @@ -679,16 +695,17 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { .thenReturn(new WallpaperColors(Color.valueOf(Color.GRAY), null, null)); Executor executor = MoreExecutors.directExecutor(); - mThemeOverlayController = new ThemeOverlayController(null /* context */, + mThemeOverlayController = new ThemeOverlayController(mContext, mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, - mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) { + mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle) { @Nullable @Override protected FabricatedOverlay getOverlay(int color, int type, Style style) { FabricatedOverlay overlay = mock(FabricatedOverlay.class); when(overlay.getIdentifier()) .thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000))); + mColorScheme = new ColorScheme(color, false /* nightMode */, style); return overlay; } }; diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt new file mode 100644 index 000000000000..5509a6cac1dd --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.unfold.progress + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.systemui.SysuiTestCase +import com.android.systemui.unfold.UnfoldTransitionProgressProvider +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener +import com.android.systemui.unfold.updates.FOLD_UPDATE_START_OPENING +import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE +import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN +import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN +import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING +import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED +import com.android.systemui.unfold.util.TestFoldStateProvider +import com.android.systemui.util.leak.ReferenceTestUtils.waitForCondition +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class PhysicsBasedUnfoldTransitionProgressProviderTest : SysuiTestCase() { + + private val foldStateProvider: TestFoldStateProvider = TestFoldStateProvider() + private val listener = TestUnfoldProgressListener() + private lateinit var progressProvider: UnfoldTransitionProgressProvider + + @Before + fun setUp() { + progressProvider = PhysicsBasedUnfoldTransitionProgressProvider( + foldStateProvider + ) + progressProvider.addCallback(listener) + } + + @Test + fun testUnfold_emitsIncreasingTransitionEvents() { + runOnMainThreadWithInterval( + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) }, + { foldStateProvider.sendHingeAngleUpdate(10f) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }, + { foldStateProvider.sendHingeAngleUpdate(90f) }, + { foldStateProvider.sendHingeAngleUpdate(180f) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }, + ) + + with(listener.ensureTransitionFinished()) { + assertIncreasingProgress() + assertFinishedWithUnfold() + } + } + + @Test + fun testUnfold_screenAvailableOnlyAfterFullUnfold_emitsIncreasingTransitionEvents() { + runOnMainThreadWithInterval( + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) }, + { foldStateProvider.sendHingeAngleUpdate(10f) }, + { foldStateProvider.sendHingeAngleUpdate(90f) }, + { foldStateProvider.sendHingeAngleUpdate(180f) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }, + ) + + with(listener.ensureTransitionFinished()) { + assertIncreasingProgress() + assertFinishedWithUnfold() + } + } + + @Test + fun testFold_emitsDecreasingTransitionEvents() { + runOnMainThreadWithInterval( + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_CLOSING) }, + { foldStateProvider.sendHingeAngleUpdate(170f) }, + { foldStateProvider.sendHingeAngleUpdate(90f) }, + { foldStateProvider.sendHingeAngleUpdate(10f) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) }, + ) + + with(listener.ensureTransitionFinished()) { + assertDecreasingProgress() + assertFinishedWithFold() + } + } + + @Test + fun testUnfoldAndStopUnfolding_finishesTheUnfoldTransition() { + runOnMainThreadWithInterval( + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }, + { foldStateProvider.sendHingeAngleUpdate(10f) }, + { foldStateProvider.sendHingeAngleUpdate(90f) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN) }, + ) + + with(listener.ensureTransitionFinished()) { + assertIncreasingProgress() + assertFinishedWithUnfold() + } + } + + @Test + fun testFoldImmediatelyAfterUnfold_runsFoldAnimation() { + runOnMainThreadWithInterval( + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_OPENING) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) }, + { foldStateProvider.sendHingeAngleUpdate(10f) }, + { foldStateProvider.sendHingeAngleUpdate(90f) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_CLOSING) }, + { foldStateProvider.sendHingeAngleUpdate(60f) }, + { foldStateProvider.sendHingeAngleUpdate(10f) }, + { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) }, + ) + + with(listener.ensureTransitionFinished()) { + assertHasFoldAnimationAtTheEnd() + } + } + + private class TestUnfoldProgressListener : TransitionProgressListener { + + private val recordings: MutableList<UnfoldTransitionRecording> = arrayListOf() + private var currentRecording: UnfoldTransitionRecording? = null + + override fun onTransitionStarted() { + assertWithMessage("Trying to start a transition when it is already in progress") + .that(currentRecording).isNull() + + currentRecording = UnfoldTransitionRecording() + } + + override fun onTransitionProgress(progress: Float) { + assertWithMessage("Received transition progress event when it's not started") + .that(currentRecording).isNotNull() + currentRecording!!.addProgress(progress) + } + + override fun onTransitionFinished() { + assertWithMessage("Received transition finish event when it's not started") + .that(currentRecording).isNotNull() + recordings += currentRecording!! + currentRecording = null + } + + fun ensureTransitionFinished(): UnfoldTransitionRecording { + waitForCondition { recordings.size == 1 } + return recordings.first() + } + + class UnfoldTransitionRecording { + private val progressHistory: MutableList<Float> = arrayListOf() + + fun addProgress(progress: Float) { + assertThat(progress).isAtMost(1.0f) + assertThat(progress).isAtLeast(0.0f) + + progressHistory += progress + } + + fun assertIncreasingProgress() { + assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) + assertThat(progressHistory).isInOrder() + } + + fun assertDecreasingProgress() { + assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) + assertThat(progressHistory).isInOrder(Comparator.reverseOrder<Float>()) + } + + fun assertFinishedWithUnfold() { + assertThat(progressHistory).isNotEmpty() + assertThat(progressHistory.last()).isEqualTo(1.0f) + } + + fun assertFinishedWithFold() { + assertThat(progressHistory).isNotEmpty() + assertThat(progressHistory.last()).isEqualTo(0.0f) + } + + fun assertHasFoldAnimationAtTheEnd() { + // Check that there are at least a few decreasing events at the end + assertThat(progressHistory.size).isGreaterThan(MIN_ANIMATION_EVENTS) + assertThat(progressHistory.takeLast(MIN_ANIMATION_EVENTS)) + .isInOrder(Comparator.reverseOrder<Float>()) + assertThat(progressHistory.last()).isEqualTo(0.0f) + } + } + + private companion object { + private const val MIN_ANIMATION_EVENTS = 5 + } + } + + private fun runOnMainThreadWithInterval(vararg blocks: () -> Unit, intervalMillis: Long = 60) { + blocks.forEach { + InstrumentationRegistry.getInstrumentation().runOnMainSync { + it() + } + Thread.sleep(intervalMillis) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt index f43dc6c5bc83..7ac243452222 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt @@ -16,6 +16,11 @@ package com.android.systemui.unfold.updates +import android.app.ActivityManager +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ActivityType import android.hardware.devicestate.DeviceStateManager import android.hardware.devicestate.DeviceStateManager.FoldStateListener import android.os.Handler @@ -30,7 +35,6 @@ import com.android.systemui.unfold.util.FoldableDeviceStates import com.android.systemui.unfold.util.FoldableTestUtils import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat -import java.lang.Exception import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -51,6 +55,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { @Mock private lateinit var deviceStateManager: DeviceStateManager + @Mock private lateinit var activityManager: ActivityManager + @Mock private lateinit var handler: Handler @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener> @@ -80,6 +86,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { hingeAngleProvider, screenStatusProvider, deviceStateManager, + activityManager, context.mainExecutor, handler) @@ -113,6 +120,9 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { } null } + + // By default, we're on launcher. + setupForegroundActivityType(ACTIVITY_TYPE_HOME) } @Test @@ -258,6 +268,31 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { } } + @Test + fun startClosingEvent_whileNotOnLauncher_doesNotTriggerBeforeThreshold() { + setupForegroundActivityType(ACTIVITY_TYPE_STANDARD) + sendHingeAngleEvent(180) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1) + + assertThat(foldUpdates).isEmpty() + } + + @Test + fun startClosingEvent_whileNotOnLauncher_triggersAfterThreshold() { + setupForegroundActivityType(ACTIVITY_TYPE_STANDARD) + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) + } + + private fun setupForegroundActivityType(@ActivityType type: Int) { + val taskInfo = RunningTaskInfo().apply { topActivityType = type } + whenever(activityManager.getRunningTasks(1)).thenReturn(listOf(taskInfo)) + } + private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) { val runnableDelay = scheduledRunnableDelay ?: throw Exception("No runnable scheduled.") if (waitTime >= runnableDelay) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt new file mode 100644 index 000000000000..dd307b4b21e9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.unfold.util + +import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN +import com.android.systemui.unfold.updates.FoldStateProvider +import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate +import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener + +class TestFoldStateProvider : FoldStateProvider { + + private val listeners: MutableList<FoldUpdatesListener> = arrayListOf() + + override fun start() { + } + + override fun stop() { + listeners.clear() + } + + private var _isFullyOpened: Boolean = false + + override val isFullyOpened: Boolean + get() = _isFullyOpened + + override fun addCallback(listener: FoldUpdatesListener) { + listeners += listener + } + + override fun removeCallback(listener: FoldUpdatesListener) { + listeners -= listener + } + + fun sendFoldUpdate(@FoldUpdate update: Int) { + if (update == FOLD_UPDATE_FINISH_FULL_OPEN) { + _isFullyOpened = true + } + listeners.forEach { it.onFoldUpdate(update) } + } + + fun sendHingeAngleUpdate(angle: Float) { + listeners.forEach { it.onHingeAngleUpdate(angle) } + } +} diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml index 0604b47cdb50..4c5c2591986f 100644 --- a/packages/VpnDialogs/res/values-or/strings.xml +++ b/packages/VpnDialogs/res/values-or/strings.xml @@ -29,7 +29,7 @@ <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇ ରହିବା ପାଇଁ ସେଟଅପ୍ କରାଯାଇଛି। ଆପଣଙ୍କ ଫୋନ୍, <xliff:g id="VPN_APP_1">%1$s</xliff:g> ସହ କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଏକ ପବ୍ଲିକ୍ ନେଟ୍ୱର୍କ ବ୍ୟବହାର କରିବ।"</string> <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> ସବୁ ସମୟରେ କନେକ୍ଟ ହୋଇରହିବାକୁ ସେଟଅପ୍ କରାଯାଇଛି, କିନ୍ତୁ ଏହା ବର୍ତ୍ତମାନ କନେକ୍ଟ କରିପାରୁ ନାହିଁ। VPN ପୁଣି କନେକ୍ଟ ନହେବା ପର୍ଯ୍ୟନ୍ତ ଆପଣଙ୍କର କୌଣସି କନେକ୍ସନ୍ ରହିବନାହିଁ।"</string> <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string> - <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଂସ୍ ବଦଳାନ୍ତୁ"</string> + <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ସେଟିଂସ ବଦଳାନ୍ତୁ"</string> <string name="configure" msgid="4905518375574791375">"କନଫିଗର୍ କରନ୍ତୁ"</string> <string name="disconnect" msgid="971412338304200056">"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string> <string name="open_app" msgid="3717639178595958667">"ଆପ୍ ଖୋଲନ୍ତୁ"</string> diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 61e3da8aae51..22c77e92842a 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -4290,11 +4290,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } private void onDoubleTapInternal(int displayId) { + AccessibilityInputFilter inputFilter = null; synchronized (mLock) { if (mHasInputFilter && mInputFilter != null) { - mInputFilter.onDoubleTap(displayId); + inputFilter = mInputFilter; } } + if (inputFilter != null) { + inputFilter.onDoubleTap(displayId); + } } @Override diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index 51b49ed1e3bc..55dc196fc18d 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -37,6 +37,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteCallbackList; import android.provider.Settings; @@ -123,8 +124,8 @@ class AccessibilityUserState { private int mInteractiveUiTimeout = 0; private int mLastSentClientState = -1; - /** {@code true} if the device config supports magnification area. */ - private final boolean mSupportMagnificationArea; + /** {@code true} if the device config supports window magnification. */ + private final boolean mSupportWindowMagnification; // The magnification modes on displays. private final SparseIntArray mMagnificationModes = new SparseIntArray(); // The magnification capabilities used to know magnification mode could be switched. @@ -148,7 +149,7 @@ class AccessibilityUserState { boolean isValidMagnificationModeLocked(int displayId) { final int mode = getMagnificationModeLocked(displayId); - if (!mSupportMagnificationArea + if (!mSupportWindowMagnification && mode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { return false; } @@ -170,8 +171,9 @@ class AccessibilityUserState { R.color.accessibility_focus_highlight_color); mFocusStrokeWidth = mFocusStrokeWidthDefaultValue; mFocusColor = mFocusColorDefaultValue; - mSupportMagnificationArea = mContext.getResources().getBoolean( - R.bool.config_magnification_area); + mSupportWindowMagnification = mContext.getResources().getBoolean( + R.bool.config_magnification_area) && mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WINDOW_MAGNIFICATION); } boolean isHandlingAccessibilityEventsLocked() { diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index 3a26c4611629..f4c24a82ae13 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -165,7 +165,10 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @Override public void onTopActivityChanged(ComponentName topActivity, int uid) { - if (mActivityListener != null) { + // Don't send onTopActivityChanged() callback when topActivity is null because it's defined + // as @NonNull in ActivityListener interface. Sends onDisplayEmpty() callback instead when + // there is no activity running on virtual display. + if (mActivityListener != null && topActivity != null) { // Post callback on the main thread so it doesn't block activity launching mHandler.post(() -> mActivityListener.onTopActivityChanged(Display.INVALID_DISPLAY, topActivity)); diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index b05a7dbe83d1..06fd5c0e9b82 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -173,6 +173,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub return flags; } + /** Returns the device display name. */ + CharSequence getDisplayName() { + return mAssociationInfo.getDisplayName(); + } + @Override // Binder call public int getAssociationId() { return mAssociationInfo.getId(); @@ -523,8 +528,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } PowerManager powerManager = mContext.getSystemService(PowerManager.class); PowerManager.WakeLock wakeLock = powerManager.newWakeLock( - PowerManager.SCREEN_BRIGHT_WAKE_LOCK - | PowerManager.ACQUIRE_CAUSES_WAKEUP, + PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG + ":" + displayId, displayId); wakeLock.acquire(); mPerDisplayWakelocks.put(displayId, wakeLock); @@ -596,6 +600,13 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub * Shows a toast on virtual displays owned by this device which have a given uid running. */ void showToastWhereUidIsRunning(int uid, @StringRes int resId, @Toast.Duration int duration) { + showToastWhereUidIsRunning(uid, mContext.getString(resId), duration); + } + + /** + * Shows a toast on virtual displays owned by this device which have a given uid running. + */ + void showToastWhereUidIsRunning(int uid, String text, @Toast.Duration int duration) { synchronized (mVirtualDeviceLock) { DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); final int size = mWindowPolicyControllers.size(); @@ -604,7 +615,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub int displayId = mWindowPolicyControllers.keyAt(i); Display display = displayManager.getDisplay(displayId); if (display != null && display.isValid()) { - Toast.makeText(mContext.createDisplayContext(display), resId, + Toast.makeText(mContext.createDisplayContext(display), text, duration).show(); } } diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index 9f252d744144..96400c1414ec 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -193,8 +193,12 @@ public class VirtualDeviceManagerService extends SystemService { synchronized (mVirtualDeviceManagerLock) { int size = mVirtualDevices.size(); for (int i = 0; i < size; i++) { + CharSequence deviceName = mVirtualDevices.valueAt(i).getDisplayName(); mVirtualDevices.valueAt(i).showToastWhereUidIsRunning(appUid, - com.android.internal.R.string.vdm_camera_access_denied, Toast.LENGTH_LONG); + getContext().getString( + com.android.internal.R.string.vdm_camera_access_denied, + deviceName), + Toast.LENGTH_LONG); } } } diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java index a2a232d6f3ec..1d457aa933d7 100644 --- a/services/core/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java @@ -60,6 +60,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IDropBoxManagerService; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.ObjectUtils; import com.android.server.DropBoxManagerInternal.EntrySource; @@ -501,12 +502,20 @@ public final class DropBoxManagerService extends SystemService { } } catch (IOException e) { Slog.e(TAG, "Can't write: " + tag, e); + logDropboxDropped( + FrameworkStatsLog.DROPBOX_ENTRY_DROPPED__DROP_REASON__WRITE_FAILURE, + tag, + 0); } finally { IoUtils.closeQuietly(entry); if (temp != null) temp.delete(); } } + private void logDropboxDropped(int reason, String tag, long entryAge) { + FrameworkStatsLog.write(FrameworkStatsLog.DROPBOX_ENTRY_DROPPED, reason, tag, entryAge); + } + public boolean isTagEnabled(String tag) { final long token = Binder.clearCallingIdentity(); try { @@ -1119,13 +1128,19 @@ public final class DropBoxManagerService extends SystemService { Settings.Global.DROPBOX_MAX_FILES, (ActivityManager.isLowRamDeviceStatic() ? DEFAULT_MAX_FILES_LOWRAM : DEFAULT_MAX_FILES)); - long cutoffMillis = System.currentTimeMillis() - ageSeconds * 1000; + long curTimeMillis = System.currentTimeMillis(); + long cutoffMillis = curTimeMillis - ageSeconds * 1000; while (!mAllFiles.contents.isEmpty()) { EntryFile entry = mAllFiles.contents.first(); if (entry.timestampMillis > cutoffMillis && mAllFiles.contents.size() < mMaxFiles) { break; } + logDropboxDropped( + FrameworkStatsLog.DROPBOX_ENTRY_DROPPED__DROP_REASON__AGED, + entry.tag, + curTimeMillis - entry.timestampMillis); + FileList tag = mFilesByTag.get(entry.tag); if (tag != null && tag.contents.remove(entry)) tag.blocks -= entry.blocks; if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks; @@ -1194,6 +1209,11 @@ public final class DropBoxManagerService extends SystemService { if (mAllFiles.blocks < mCachedQuotaBlocks) break; while (tag.blocks > tagQuota && !tag.contents.isEmpty()) { EntryFile entry = tag.contents.first(); + logDropboxDropped( + FrameworkStatsLog.DROPBOX_ENTRY_DROPPED__DROP_REASON__CLEARING_DATA, + entry.tag, + curTimeMillis - entry.timestampMillis); + if (tag.contents.remove(entry)) tag.blocks -= entry.blocks; if (mAllFiles.contents.remove(entry)) mAllFiles.blocks -= entry.blocks; diff --git a/services/core/java/com/android/server/FactoryResetter.java b/services/core/java/com/android/server/FactoryResetter.java new file mode 100644 index 000000000000..30314a3683a6 --- /dev/null +++ b/services/core/java/com/android/server/FactoryResetter.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.content.pm.PackageManager; + +import com.android.internal.util.Preconditions; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * TODO(b/225012970): add javadoc from {@code com.android.server.devicepolicy.FactoryResetter} + */ +public final class FactoryResetter { + + private static final AtomicBoolean sFactoryResetting = new AtomicBoolean(false); + + /** + * Checks whether a factory reset is in progress. + */ + public static boolean isFactoryResetting() { + return sFactoryResetting.get(); + } + + /** + * @deprecated called by {@code com.android.server.devicepolicy.FactoryResetter}, won't be + * needed once that class logic is moved into this. + */ + @Deprecated + public static void setFactoryResetting(Context context) { + Preconditions.checkCallAuthorization(context.checkCallingOrSelfPermission( + android.Manifest.permission.MASTER_CLEAR) == PackageManager.PERMISSION_GRANTED); + sFactoryResetting.set(true); + } + + private FactoryResetter() { + throw new UnsupportedOperationException("Provides only static methods"); + } +} diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index 593c406ed47b..59db68691223 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -129,15 +129,15 @@ public class MmsServiceBroker extends SystemService { @Override public void sendMessage(int subId, String callingPkg, Uri contentUri, String locationUrl, - Bundle configOverrides, PendingIntent sentIntent, long messageId) - throws RemoteException { + Bundle configOverrides, PendingIntent sentIntent, long messageId, + String attributionTag) throws RemoteException { returnPendingIntentWithError(sentIntent); } @Override public void downloadMessage(int subId, String callingPkg, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent, - long messageId) + long messageId, String attributionTag) throws RemoteException { returnPendingIntentWithError(downloadedIntent); } @@ -333,12 +333,12 @@ public class MmsServiceBroker extends SystemService { @Override public void sendMessage(int subId, String callingPkg, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent, - long messageId) + long messageId, String attributionTag) throws RemoteException { Slog.d(TAG, "sendMessage() by " + callingPkg); mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message"); if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, attributionTag, null) != AppOpsManager.MODE_ALLOWED) { Slog.e(TAG, callingPkg + " is not allowed to call sendMessage()"); return; } @@ -347,18 +347,18 @@ public class MmsServiceBroker extends SystemService { Intent.FLAG_GRANT_READ_URI_PERMISSION, subId); getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl, - configOverrides, sentIntent, messageId); + configOverrides, sentIntent, messageId, attributionTag); } @Override public void downloadMessage(int subId, String callingPkg, String locationUrl, - Uri contentUri, Bundle configOverrides, - PendingIntent downloadedIntent, long messageId) throws RemoteException { + Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent, + long messageId, String attributionTag) throws RemoteException { Slog.d(TAG, "downloadMessage() by " + callingPkg); mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS, "Download MMS message"); if (getAppOpsManager().noteOp(AppOpsManager.OP_RECEIVE_MMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, attributionTag, null) != AppOpsManager.MODE_ALLOWED) { Slog.e(TAG, callingPkg + " is not allowed to call downloadMessage()"); return; } @@ -368,14 +368,14 @@ public class MmsServiceBroker extends SystemService { subId); getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri, - configOverrides, downloadedIntent, messageId); + configOverrides, downloadedIntent, messageId, attributionTag); } @Override public Uri importTextMessage(String callingPkg, String address, int type, String text, long timestampMillis, boolean seen, boolean read) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { // Silently fail AppOps failure due to not being the default SMS app // while writing the TelephonyProvider return FAKE_SMS_SENT_URI; @@ -389,7 +389,7 @@ public class MmsServiceBroker extends SystemService { String messageId, long timestampSecs, boolean seen, boolean read) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { // Silently fail AppOps failure due to not being the default SMS app // while writing the TelephonyProvider return FAKE_MMS_SENT_URI; @@ -402,7 +402,7 @@ public class MmsServiceBroker extends SystemService { public boolean deleteStoredMessage(String callingPkg, Uri messageUri) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { return false; } return getServiceGuarded().deleteStoredMessage(callingPkg, messageUri); @@ -412,7 +412,7 @@ public class MmsServiceBroker extends SystemService { public boolean deleteStoredConversation(String callingPkg, long conversationId) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { return false; } return getServiceGuarded().deleteStoredConversation(callingPkg, conversationId); @@ -422,7 +422,7 @@ public class MmsServiceBroker extends SystemService { public boolean updateStoredMessageStatus(String callingPkg, Uri messageUri, ContentValues statusValues) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { return false; } return getServiceGuarded() @@ -433,7 +433,7 @@ public class MmsServiceBroker extends SystemService { public boolean archiveStoredConversation(String callingPkg, long conversationId, boolean archived) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { return false; } return getServiceGuarded() @@ -444,7 +444,7 @@ public class MmsServiceBroker extends SystemService { public Uri addTextMessageDraft(String callingPkg, String address, String text) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { // Silently fail AppOps failure due to not being the default SMS app // while writing the TelephonyProvider return FAKE_SMS_DRAFT_URI; @@ -456,7 +456,7 @@ public class MmsServiceBroker extends SystemService { public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { // Silently fail AppOps failure due to not being the default SMS app // while writing the TelephonyProvider return FAKE_MMS_DRAFT_URI; @@ -468,7 +468,7 @@ public class MmsServiceBroker extends SystemService { public void sendStoredMessage(int subId, String callingPkg, Uri messageUri, Bundle configOverrides, PendingIntent sentIntent) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { return; } getServiceGuarded().sendStoredMessage(subId, callingPkg, messageUri, configOverrides, @@ -478,7 +478,7 @@ public class MmsServiceBroker extends SystemService { @Override public void setAutoPersisting(String callingPkg, boolean enabled) throws RemoteException { if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(), - callingPkg) != AppOpsManager.MODE_ALLOWED) { + callingPkg, null, null) != AppOpsManager.MODE_ALLOWED) { return; } getServiceGuarded().setAutoPersisting(callingPkg, enabled); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 1a39ffa393b3..73d9cc759b10 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1528,7 +1528,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { if (updateFirewallUidRuleLocked(chain, uid, rule)) { final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); try { - cm.updateFirewallRule(chain, uid, isFirewallRuleAllow(chain, rule)); + cm.setUidFirewallRule(chain, uid, rule); } catch (RuntimeException e) { throw new IllegalStateException(e); } @@ -1601,14 +1601,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } - // There are only two type of firewall rule: FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY. - private boolean isFirewallRuleAllow(int chain, int rule) { - if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) { - return getFirewallType(chain) == FIREWALL_DENYLIST; - } - return rule == INetd.FIREWALL_RULE_ALLOW; - } - private void enforceSystemUid() { final int uid = mDeps.getCallingUid(); if (uid != Process.SYSTEM_UID) { diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index b6b3618a5888..24e5de9aa9a0 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -1,9 +1,6 @@ { "presubmit": [ { - "name": "CtsLocationFineTestCases" - }, - { "name": "CtsLocationCoarseTestCases" }, { @@ -64,5 +61,10 @@ ], "file_patterns": ["ClipboardService\\.java"] } + ], + "postsubmit": [ + { + "name": "CtsLocationFineTestCases" + } ] } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index b0ab5390724b..2643bed44e2e 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -203,10 +203,6 @@ public final class ActiveServices { // How long we wait for a service to finish executing. static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; - // How long the startForegroundService() grace period is to get around to - // calling startForeground() before we ANR + stop it. - static final int SERVICE_START_FOREGROUND_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER; - // Foreground service types that always get immediate notification display, // expressed in the same bitmask format that ServiceRecord.foregroundServiceType // uses. @@ -2789,6 +2785,11 @@ public final class ActiveServices { + ") set BIND_ALLOW_INSTANT when binding service " + service); } + if ((flags & Context.BIND_ALMOST_PERCEPTIBLE) != 0 && !isCallerSystem) { + throw new SecurityException("Non-system caller (pid=" + callingPid + + ") set BIND_ALMOST_PERCEPTIBLE when binding service " + service); + } + if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) { mAm.enforceCallingPermission( android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, @@ -4235,7 +4236,7 @@ public final class ActiveServices { + " for fg-service launch"); } mAm.tempAllowlistUidLocked(r.appInfo.uid, - SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH, + mAm.mConstants.mServiceStartForegroundTimeoutMs, REASON_SERVICE_LAUNCH, "fg-service-launch", TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, r.mRecentCallingUid); @@ -5708,12 +5709,23 @@ public final class ActiveServices { } if (app != null) { - mAm.mAnrHelper.appNotResponding(app, - "Context.startForegroundService() did not then call Service.startForeground(): " - + r); + final String annotation = "Context.startForegroundService() did not then call " + + "Service.startForeground(): " + r; + Message msg = mAm.mHandler.obtainMessage( + ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_ANR_MSG); + SomeArgs args = SomeArgs.obtain(); + args.arg1 = app; + args.arg2 = annotation; + msg.obj = args; + mAm.mHandler.sendMessageDelayed(msg, + mAm.mConstants.mServiceStartForegroundAnrDelayMs); } } + void serviceForegroundTimeoutANR(ProcessRecord app, String annotation) { + mAm.mAnrHelper.appNotResponding(app, annotation); + } + public void updateServiceApplicationInfoLocked(ApplicationInfo applicationInfo) { final int userId = UserHandle.getUserId(applicationInfo.uid); ServiceMap serviceMap = mServiceMap.get(userId); @@ -5734,7 +5746,7 @@ public final class ActiveServices { ComponentName service) { mAm.crashApplicationWithTypeWithExtras( app.uid, app.getPid(), app.info.packageName, app.userId, - "Context.startForegroundService() did not then call Service.startForeground(): " + "Context.startForegroundService() did not then call " + "Service.startForeground(): " + serviceRecord, false /*force*/, ForegroundServiceDidNotStartInTimeException.TYPE_ID, ForegroundServiceDidNotStartInTimeException.createExtrasForService(service)); @@ -5759,7 +5771,7 @@ public final class ActiveServices { ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG); msg.obj = r; r.fgWaiting = true; - mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT); + mAm.mHandler.sendMessageDelayed(msg, mAm.mConstants.mServiceStartForegroundTimeoutMs); } final class ServiceDumper { diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index cc8c6fb6c23a..39a670ea7dbe 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -216,8 +216,12 @@ final class ActivityManagerConstants extends ContentObserver { private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = ""; private static final int DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST = - DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY - | DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY; + DEFER_BOOT_COMPLETED_BROADCAST_BACKGROUND_RESTRICTED_ONLY + | DEFER_BOOT_COMPLETED_BROADCAST_TARGET_T_ONLY; + + private static final int DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS = 30 * 1000; + + private static final int DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS = 10 * 1000; // Flag stored in the DeviceConfig API. /** @@ -311,6 +315,12 @@ final class ActivityManagerConstants extends ContentObserver { private static final String KEY_DEFER_BOOT_COMPLETED_BROADCAST = "defer_boot_completed_broadcast"; + private static final String KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS = + "service_start_foreground_timeout_ms"; + + private static final String KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS = + "service_start_foreground_anr_delay_ms"; + // Maximum number of cached processes we will allow. public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; @@ -631,6 +641,19 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST; /** + * How long the Context.startForegroundService() grace period is to get around to + * calling Service.startForeground() before we generate ANR. + */ + volatile int mServiceStartForegroundTimeoutMs = DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS; + + /** + * How long from Service.startForeground() timed-out to when we generate ANR of the user app. + * This delay is after the timeout {@link #mServiceStartForegroundTimeoutMs}. + */ + volatile int mServiceStartForegroundAnrDelayMs = + DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS; + + /** * Defines component aliases. Format * ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )* */ @@ -913,6 +936,12 @@ final class ActivityManagerConstants extends ContentObserver { case KEY_DEFER_BOOT_COMPLETED_BROADCAST: updateDeferBootCompletedBroadcast(); break; + case KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS: + updateServiceStartForegroundTimeoutMs(); + break; + case KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS: + updateServiceStartForegroundAnrDealyMs(); + break; case KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED: updateNoKillCachedProcessesUntilBootCompleted(); break; @@ -1389,6 +1418,20 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_MAX_EMPTY_TIME_MILLIS); } + private void updateServiceStartForegroundTimeoutMs() { + mServiceStartForegroundTimeoutMs = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS, + DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS); + } + + private void updateServiceStartForegroundAnrDealyMs() { + mServiceStartForegroundAnrDelayMs = DeviceConfig.getInt( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS, + DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS); + } + private long[] parseLongArray(@NonNull String key, @NonNull long[] def) { final String val = DeviceConfig.getString(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, key, null); @@ -1669,6 +1712,10 @@ final class ActivityManagerConstants extends ContentObserver { pw.print("="); pw.println(mNoKillCachedProcessesPostBootCompletedDurationMillis); pw.print(" "); pw.print(KEY_MAX_EMPTY_TIME_MILLIS); pw.print("="); pw.println(mMaxEmptyTimeMillis); + pw.print(" "); pw.print(KEY_SERVICE_START_FOREGROUND_TIMEOUT_MS); + pw.print("="); pw.println(mServiceStartForegroundTimeoutMs); + pw.print(" "); pw.print(KEY_SERVICE_START_FOREGROUND_ANR_DELAY_MS); + pw.print("="); pw.println(mServiceStartForegroundAnrDelayMs); pw.println(); if (mOverrideMaxCachedProcesses >= 0) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c40f65f54210..c45b9f24dfed 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1536,6 +1536,7 @@ public class ActivityManagerService extends IActivityManager.Stub static final int IDLE_UIDS_MSG = 58; static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63; static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66; + static final int SERVICE_FOREGROUND_TIMEOUT_ANR_MSG = 67; static final int PUSH_TEMP_ALLOWLIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; @@ -1724,6 +1725,12 @@ public class ActivityManagerService extends IActivityManager.Stub case SERVICE_FOREGROUND_TIMEOUT_MSG: { mServices.serviceForegroundTimeout((ServiceRecord) msg.obj); } break; + case SERVICE_FOREGROUND_TIMEOUT_ANR_MSG: { + SomeArgs args = (SomeArgs) msg.obj; + mServices.serviceForegroundTimeoutANR((ProcessRecord) args.arg1, + (String) args.arg2); + args.recycle(); + } break; case SERVICE_FOREGROUND_CRASH_MSG: { SomeArgs args = (SomeArgs) msg.obj; mServices.serviceForegroundCrash( @@ -12938,7 +12945,12 @@ public class ActivityManagerService extends IActivityManager.Stub public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage, String callerFeatureId, String receiverId, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { - enforceNotIsolatedOrSdkSandboxCaller("registerReceiver"); + // Allow Sandbox process to register only unexported receivers. + if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) { + enforceNotIsolatedCaller("registerReceiver"); + } else { + enforceNotIsolatedOrSdkSandboxCaller("registerReceiver"); + } ArrayList<Intent> stickyIntents = null; ProcessRecord callerApp = null; final boolean visibleToInstantApps @@ -17258,8 +17270,8 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void deletePendingTopUid(int uid) { - mPendingStartActivityUids.delete(uid); + public void deletePendingTopUid(int uid, long nowElapsed) { + mPendingStartActivityUids.delete(uid, nowElapsed); } @Override @@ -17362,6 +17374,11 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public int getServiceStartForegroundTimeout() { + return mConstants.mServiceStartForegroundTimeoutMs; + } + + @Override public int getUidCapability(int uid) { synchronized (ActivityManagerService.this) { UidRecord uidRecord = mProcessList.getUidRecordLOSP(uid); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 2b61e7fd2752..5024a4a1cba0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -183,6 +183,7 @@ final class ActivityManagerShellCommand extends ShellCommand { private boolean mAsync; private BroadcastOptions mBroadcastOptions; private boolean mShowSplashScreen; + private boolean mDismissKeyguardIfInsecure; final boolean mDumping; @@ -439,6 +440,8 @@ final class ActivityManagerShellCommand extends ShellCommand { mAsync = true; } else if (opt.equals("--splashscreen-show-icon")) { mShowSplashScreen = true; + } else if (opt.equals("--dismiss-keyguard-if-insecure")) { + mDismissKeyguardIfInsecure = true; } else { return false; } @@ -583,6 +586,12 @@ final class ActivityManagerShellCommand extends ShellCommand { } options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); } + if (mDismissKeyguardIfInsecure) { + if (options == null) { + options = ActivityOptions.makeBasic(); + } + options.setDismissKeyguardIfInsecure(); + } if (mWaitOption) { result = mInternal.startActivityAndWait(null, SHELL_PACKAGE_NAME, null, intent, mimeType, null, null, 0, mStartFlags, profilerInfo, diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java index 2f76e2497834..cb21a4bf8f22 100644 --- a/services/core/java/com/android/server/am/BaseAppStateTracker.java +++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java @@ -16,7 +16,6 @@ package com.android.server.am; -import static com.android.server.am.ActiveServices.SERVICE_START_FOREGROUND_TIMEOUT; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -362,7 +361,7 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> { } long getServiceStartForegroundTimeout() { - return SERVICE_START_FOREGROUND_TIMEOUT; + return mActivityManagerInternal.getServiceStartForegroundTimeout(); } RoleManager getRoleManager() { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 9626bbe0b4b2..d6351527de6d 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1254,7 +1254,7 @@ public class OomAdjuster { mService.mServices.foregroundServiceProcStateChangedLocked(uidRec); } } - mService.mInternal.deletePendingTopUid(uidRec.getUid()); + mService.mInternal.deletePendingTopUid(uidRec.getUid(), nowElapsed); } if (mLocalPowerManager != null) { mLocalPowerManager.finishUidChanges(); @@ -2854,8 +2854,7 @@ public class OomAdjuster { // To avoid some abuse patterns, we are going to be careful about what we consider // to be an app interaction. Being the top activity doesn't count while the display // is sleeping, nor do short foreground services. - if (state.getCurProcState() <= PROCESS_STATE_TOP - || state.getCurProcState() == PROCESS_STATE_BOUND_TOP) { + if (ActivityManager.isProcStateConsideredInteraction(state.getCurProcState())) { isInteraction = true; state.setFgInteractionTime(0); } else if (state.getCurProcState() <= PROCESS_STATE_FOREGROUND_SERVICE) { diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java index 455c75b88218..bd600571f0a3 100644 --- a/services/core/java/com/android/server/am/PendingStartActivityUids.java +++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java @@ -55,9 +55,15 @@ final class PendingStartActivityUids { return false; } - synchronized void delete(int uid) { + synchronized void delete(int uid, long nowElapsed) { final Pair<Integer, Long> pendingPid = mPendingUids.get(uid); if (pendingPid != null) { + if (nowElapsed < pendingPid.second) { + Slog.i(TAG, + "updateOomAdj start time is before than pendingPid added," + + " don't delete it"); + return; + } final long delay = SystemClock.elapsedRealtime() - pendingPid.second; if (delay >= 1000 /*ms*/) { Slog.i(TAG, @@ -87,4 +93,4 @@ final class PendingStartActivityUids { synchronized boolean isPendingTopUid(int uid) { return mPendingUids.get(uid) != null; } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 879534778800..b886196755ea 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -107,6 +107,7 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockPatternUtils; +import com.android.server.FactoryResetter; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemService.UserCompletedEventType; @@ -1797,6 +1798,10 @@ class UserController implements Handler.Callback { Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user"); return false; } + if (FactoryResetter.isFactoryResetting()) { + Slogf.w(TAG, "Cannot switch to User #" + targetUserId + ": factory reset in progress"); + return false; + } boolean userSwitchUiEnabled; synchronized (mLock) { if (!mInitialized) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 270a61b32390..1a482e47e5c3 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -252,8 +252,8 @@ import java.util.concurrent.atomic.AtomicBoolean; return; } } - setCommunicationRouteForClient( - cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource); + postSetCommunicationRouteForClient(new CommunicationClientInfo( + cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource)); } } } @@ -283,8 +283,8 @@ import java.util.concurrent.atomic.AtomicBoolean; return false; } } - setCommunicationRouteForClient( - cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource); + postSetCommunicationRouteForClient(new CommunicationClientInfo( + cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource)); } } return true; @@ -348,26 +348,35 @@ import java.util.concurrent.atomic.AtomicBoolean; } /** - * Returns the device currently requested for communication use case. - * If the current audio mode owner is in the communication route client list, - * use this preference. - * Otherwise use first client's preference (first client corresponds to latest request). - * null is returned if no client is in the list. - * @return AudioDeviceAttributes the requested device for communication. + * Returns the communication client with the highest priority: + * - 1) the client which is currently also controlling the audio mode + * - 2) the first client in the stack if there is no audio mode owner + * - 3) no client otherwise + * @return CommunicationRouteClient the client driving the communication use case routing. */ - @GuardedBy("mDeviceStateLock") - private AudioDeviceAttributes requestedCommunicationDevice() { - AudioDeviceAttributes device = null; - for (CommunicationRouteClient cl : mCommunicationRouteClients) { - if (cl.getPid() == mModeOwnerPid) { - device = cl.getDevice(); + private CommunicationRouteClient topCommunicationRouteClient() { + for (CommunicationRouteClient crc : mCommunicationRouteClients) { + if (crc.getPid() == mModeOwnerPid) { + return crc; } } if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) { - device = mCommunicationRouteClients.get(0).getDevice(); + return mCommunicationRouteClients.get(0); } + return null; + } + /** + * Returns the device currently requested for communication use case. + * Use the device requested by the communication route client selected by + * {@link #topCommunicationRouteClient()} if any or none otherwise. + * @return AudioDeviceAttributes the requested device for communication. + */ + @GuardedBy("mDeviceStateLock") + private AudioDeviceAttributes requestedCommunicationDevice() { + CommunicationRouteClient crc = topCommunicationRouteClient(); + AudioDeviceAttributes device = crc != null ? crc.getDevice() : null; if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "requestedCommunicationDevice, device: " + device + " mode owner pid: " + mModeOwnerPid); @@ -710,7 +719,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } synchronized (mDeviceStateLock) { mBluetoothScoOn = on; - sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); + postUpdateCommunicationRouteClient(eventSource); } } @@ -770,7 +779,9 @@ import java.util.concurrent.atomic.AtomicBoolean; synchronized (mDeviceStateLock) { AudioDeviceAttributes device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""); - setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource); + + postSetCommunicationRouteForClient(new CommunicationClientInfo( + cb, pid, device, scoAudioMode, eventSource)); } } } @@ -788,8 +799,8 @@ import java.util.concurrent.atomic.AtomicBoolean; if (client == null || !client.requestsBluetoothSco()) { return; } - setCommunicationRouteForClient( - cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource); + postSetCommunicationRouteForClient(new CommunicationClientInfo( + cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource)); } } } @@ -990,6 +1001,61 @@ import java.util.concurrent.atomic.AtomicBoolean; MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset); } + /*package*/ void postUpdateCommunicationRouteClient(String eventSource) { + sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource); + } + + /*package*/ void postSetCommunicationRouteForClient(CommunicationClientInfo info) { + sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT, SENDMSG_QUEUE, info); + } + + /*package*/ void postScoAudioStateChanged(int state) { + sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state); + } + + /*package*/ static final class CommunicationClientInfo { + final @NonNull IBinder mCb; + final int mPid; + final @NonNull AudioDeviceAttributes mDevice; + final int mScoAudioMode; + final @NonNull String mEventSource; + + CommunicationClientInfo(@NonNull IBinder cb, int pid, @NonNull AudioDeviceAttributes device, + int scoAudioMode, @NonNull String eventSource) { + mCb = cb; + mPid = pid; + mDevice = device; + mScoAudioMode = scoAudioMode; + mEventSource = eventSource; + } + + // redefine equality op so we can match messages intended for this client + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } + if (this == o) { + return true; + } + if (!(o instanceof CommunicationClientInfo)) { + return false; + } + + return mCb.equals(((CommunicationClientInfo) o).mCb) + && mPid == ((CommunicationClientInfo) o).mPid; + } + + @Override + public String toString() { + return "CommunicationClientInfo mCb=" + mCb.toString() + +"mPid=" + mPid + +"mDevice=" + mDevice.toString() + +"mScoAudioMode=" + mScoAudioMode + +"mEventSource=" + mEventSource; + } + } + //--------------------------------------------------------------------- // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) // only call from a "handle"* method or "on"* method @@ -1265,18 +1331,30 @@ import java.util.concurrent.atomic.AtomicBoolean; synchronized (mDeviceStateLock) { mModeOwnerPid = msg.arg1; if (msg.arg2 != AudioSystem.MODE_RINGTONE) { - onUpdateCommunicationRoute("setNewModeOwner"); + onUpdateCommunicationRouteClient("setNewModeOwner"); } } } break; - case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED: + + case MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { - onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj); + CommunicationClientInfo info = (CommunicationClientInfo) msg.obj; + setCommunicationRouteForClient(info.mCb, info.mPid, info.mDevice, + info.mScoAudioMode, info.mEventSource); + } + } + break; + + case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT: + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + onUpdateCommunicationRouteClient((String) msg.obj); } } break; + case MSG_L_UPDATE_COMMUNICATION_ROUTE: synchronized (mSetModeLock) { synchronized (mDeviceStateLock) { @@ -1284,6 +1362,23 @@ import java.util.concurrent.atomic.AtomicBoolean; } } break; + + case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED: + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj); + } + } + break; + + case MSG_I_SCO_AUDIO_STATE_CHANGED: + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + mBtHelper.onScoAudioStateChanged(msg.arg1); + } + } + break; + case MSG_TOGGLE_HDMI: synchronized (mDeviceStateLock) { mDeviceInventory.onToggleHdmi(); @@ -1437,6 +1532,9 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39; private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40; private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41; + private static final int MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT = 42; + private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43; + private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44; private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45; // @@ -1679,9 +1777,8 @@ import java.util.concurrent.atomic.AtomicBoolean; return; } Log.w(TAG, "Communication client died"); - setCommunicationRouteForClient( - client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED, - "onCommunicationRouteClientDied"); + removeCommunicationRouteClient(client.getBinder(), true); + onUpdateCommunicationRouteClient("onCommunicationRouteClientDied"); } /** @@ -1735,11 +1832,31 @@ import java.util.concurrent.atomic.AtomicBoolean; AudioSystem.setParameters("BT_SCO=on"); } if (preferredCommunicationDevice == null) { - postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); + removePreferredDevicesForStrategySync(mCommunicationStrategyId); } else { - postSetPreferredDevicesForStrategy( + setPreferredDevicesForStrategySync( mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); } + onUpdatePhoneStrategyDevice(preferredCommunicationDevice); + } + + /** + * Select new communication device from communication route client at the top of the stack + * and restore communication route including restarting SCO audio if needed. + */ + // @GuardedBy("mSetModeLock") + @GuardedBy("mDeviceStateLock") + private void onUpdateCommunicationRouteClient(String eventSource) { + onUpdateCommunicationRoute(eventSource); + CommunicationRouteClient crc = topCommunicationRouteClient(); + if (AudioService.DEBUG_COMM_RTE) { + Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + + crc + " eventSource: " + eventSource); + } + if (crc != null) { + setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(), + BtHelper.SCO_MODE_UNDEFINED, eventSource); + } } private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 0e290410d288..69b75e6e8edb 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -1154,6 +1154,7 @@ public class AudioDeviceInventory { mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address), new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT)); mDeviceBroker.postAccessoryPlugMediaUnmute(device); + setCurrentAudioRouteNameIfPossible(name, /*fromA2dp=*/false); } if (streamType == AudioSystem.STREAM_DEFAULT) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a68fc05dbbf1..d7755810f37b 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -78,6 +78,7 @@ import android.media.AudioAttributes; import android.media.AudioAttributes.AttributeSystemUsage; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; +import android.media.AudioDeviceVolumeManager; import android.media.AudioFocusInfo; import android.media.AudioFocusRequest; import android.media.AudioFormat; @@ -154,6 +155,7 @@ import android.service.notification.ZenModeConfig; import android.telecom.TelecomManager; import android.text.TextUtils; import android.util.AndroidRuntimeException; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.IntArray; import android.util.Log; @@ -627,6 +629,47 @@ public class AudioService extends IAudioService.Stub AudioSystem.DEVICE_OUT_HDMI_ARC, AudioSystem.DEVICE_OUT_HDMI_EARC )); + + // Devices where the framework sends a full scale audio signal, and controls the volume of + // the external audio system separately. + Map<Integer, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>(); + + /** + * Stores information about a device using absolute volume behavior. + */ + private static final class AbsoluteVolumeDeviceInfo { + private final AudioDeviceAttributes mDevice; + private final List<VolumeInfo> mVolumeInfos; + private final IAudioDeviceVolumeDispatcher mCallback; + private final boolean mHandlesVolumeAdjustment; + + private AbsoluteVolumeDeviceInfo(AudioDeviceAttributes device, List<VolumeInfo> volumeInfos, + IAudioDeviceVolumeDispatcher callback, boolean handlesVolumeAdjustment) { + this.mDevice = device; + this.mVolumeInfos = volumeInfos; + this.mCallback = callback; + this.mHandlesVolumeAdjustment = handlesVolumeAdjustment; + } + + /** + * Given a stream type, returns a matching VolumeInfo. + */ + @Nullable + private VolumeInfo getMatchingVolumeInfoForStream(int streamType) { + for (VolumeInfo volumeInfo : mVolumeInfos) { + boolean streamTypeMatches = volumeInfo.hasStreamType() + && volumeInfo.getStreamType() == streamType; + boolean volumeGroupMatches = volumeInfo.hasVolumeGroup() + && Arrays.stream(volumeInfo.getVolumeGroup().getLegacyStreamTypes()) + .anyMatch(s -> s == streamType); + if (streamTypeMatches || volumeGroupMatches) { + return volumeInfo; + } + } + return null; + } + } + // Devices for the which use the "absolute volume" concept (framework sends audio signal // full scale, and volume control separately) and can be used for multiple use cases reflected // by the audio mode (e.g. media playback in MODE_NORMAL, and phone calls in MODE_IN_CALL). @@ -1325,14 +1368,18 @@ public class AudioService extends IAudioService.Stub mRm = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE); if (mRm != null) { mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL); - updateAssistantUId(true); + synchronized (mSettingsLock) { + updateAssistantUIdLocked(/* forceUpdate= */ true); + } } } @Override public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { if (RoleManager.ROLE_ASSISTANT.equals(roleName)) { - updateAssistantUId(false); + synchronized (mSettingsLock) { + updateAssistantUIdLocked(/* forceUpdate= */ false); + } } } @@ -1431,7 +1478,7 @@ public class AudioService extends IAudioService.Stub sendEncodedSurroundMode(mContentResolver, "onAudioServerDied"); sendEnabledSurroundFormats(mContentResolver, true); AudioSystem.setRttEnabled(mRttEnabled); - updateAssistantServicesUidsLocked(); + resetAssistantServicesUidsLocked(); } synchronized (mAccessibilityServiceUidsLock) { @@ -1560,6 +1607,12 @@ public class AudioService extends IAudioService.Stub } @GuardedBy("mSettingsLock") + private void resetAssistantServicesUidsLocked() { + mAssistantUids.clear(); + updateAssistantUIdLocked(/* forceUpdate= */ true); + } + + @GuardedBy("mSettingsLock") private void updateAssistantServicesUidsLocked() { int[] assistantUids = mAssistantUids.stream().mapToInt(Integer::intValue).toArray(); AudioSystem.setAssistantServicesUids(assistantUids); @@ -2343,7 +2396,7 @@ public class AudioService extends IAudioService.Stub } @GuardedBy("mSettingsLock") - private void updateAssistantUId(boolean forceUpdate) { + private void updateAssistantUIdLocked(boolean forceUpdate) { int assistantUid = INVALID_UID; // Consider assistants in the following order of priority: // 1) apk in assistant role @@ -2441,7 +2494,7 @@ public class AudioService extends IAudioService.Stub readDockAudioSettings(cr); sendEncodedSurroundMode(cr, "readPersistedSettings"); sendEnabledSurroundFormats(cr, true); - updateAssistantUId(true); + updateAssistantUIdLocked(/* forceUpdate= */ true); resetActiveAssistantUidsLocked(); AudioSystem.setRttEnabled(mRttEnabled); } @@ -2509,17 +2562,44 @@ public class AudioService extends IAudioService.Stub return (mStreamStates[streamType].getMaxIndex() - mStreamStates[streamType].getMinIndex()); } + private int rescaleIndex(VolumeInfo volumeInfo, int dstStream) { + if (volumeInfo.getVolumeIndex() == VolumeInfo.INDEX_NOT_SET + || volumeInfo.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET + || volumeInfo.getMaxVolumeIndex() == VolumeInfo.INDEX_NOT_SET) { + Log.e(TAG, "rescaleIndex: volumeInfo has invalid index or range"); + return mStreamStates[dstStream].getMinIndex(); + } + return rescaleIndex(volumeInfo.getVolumeIndex(), + volumeInfo.getMinVolumeIndex(), volumeInfo.getMaxVolumeIndex(), + mStreamStates[dstStream].getMinIndex(), mStreamStates[dstStream].getMaxIndex()); + } + + private int rescaleIndex(int index, int srcStream, VolumeInfo dstVolumeInfo) { + int dstMin = dstVolumeInfo.getMinVolumeIndex(); + int dstMax = dstVolumeInfo.getMaxVolumeIndex(); + // Don't rescale index if the VolumeInfo is missing a min or max index + if (dstMin == VolumeInfo.INDEX_NOT_SET || dstMax == VolumeInfo.INDEX_NOT_SET) { + return index; + } + return rescaleIndex(index, + mStreamStates[srcStream].getMinIndex(), mStreamStates[srcStream].getMaxIndex(), + dstMin, dstMax); + } + private int rescaleIndex(int index, int srcStream, int dstStream) { - int srcRange = getIndexRange(srcStream); - int dstRange = getIndexRange(dstStream); + return rescaleIndex(index, + mStreamStates[srcStream].getMinIndex(), mStreamStates[srcStream].getMaxIndex(), + mStreamStates[dstStream].getMinIndex(), mStreamStates[dstStream].getMaxIndex()); + } + + private int rescaleIndex(int index, int srcMin, int srcMax, int dstMin, int dstMax) { + int srcRange = srcMax - srcMin; + int dstRange = dstMax - dstMin; if (srcRange == 0) { Log.e(TAG, "rescaleIndex : index range should not be zero"); - return mStreamStates[dstStream].getMinIndex(); + return dstMin; } - - return mStreamStates[dstStream].getMinIndex() - + ((index - mStreamStates[srcStream].getMinIndex()) * dstRange + srcRange / 2) - / srcRange; + return dstMin + ((index - srcMin) * dstRange + srcRange / 2) / srcRange; } private int rescaleStep(int step, int srcStream, int dstStream) { @@ -2752,26 +2832,19 @@ public class AudioService extends IAudioService.Stub return mAudioSystem.getDevicesForAttributes(attributes, forVolume); } - /** Indicates no special treatment in the handling of the volume adjustement */ - private static final int VOL_ADJUST_NORMAL = 0; - /** Indicates the start of a volume adjustement */ - private static final int VOL_ADJUST_START = 1; - /** Indicates the end of a volume adjustment */ - private static final int VOL_ADJUST_END = 2; - // pre-condition: event.getKeyCode() is one of KeyEvent.KEYCODE_VOLUME_UP, // KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_MUTE public void handleVolumeKey(@NonNull KeyEvent event, boolean isOnTv, @NonNull String callingPackage, @NonNull String caller) { - int keyEventMode = VOL_ADJUST_NORMAL; + int keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_NORMAL; if (isOnTv) { if (event.getAction() == KeyEvent.ACTION_DOWN) { - keyEventMode = VOL_ADJUST_START; + keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_START; } else { // may catch more than ACTION_UP, but will end vol adjustement // the vol key is either released (ACTION_UP), or multiple keys are pressed // (ACTION_MULTIPLE) and we don't know what to do for volume control on CEC, end // the repeated volume adjustement - keyEventMode = VOL_ADJUST_END; + keyEventMode = AudioDeviceVolumeManager.ADJUST_MODE_END; } } else if (event.getAction() != KeyEvent.ACTION_DOWN) { return; @@ -2796,7 +2869,7 @@ public class AudioService extends IAudioService.Stub adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE, AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller, Binder.getCallingUid(), Binder.getCallingPid(), - true, VOL_ADJUST_NORMAL); + true, AudioDeviceVolumeManager.ADJUST_MODE_NORMAL); } break; default: @@ -2941,7 +3014,7 @@ public class AudioService extends IAudioService.Stub direction/*val1*/, flags/*val2*/, callingPackage)); adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage, Binder.getCallingUid(), Binder.getCallingPid(), attributionTag, - callingHasAudioSettingsPermission(), VOL_ADJUST_NORMAL); + callingHasAudioSettingsPermission(), AudioDeviceVolumeManager.ADJUST_MODE_NORMAL); } protected void adjustStreamVolume(int streamType, int direction, int flags, @@ -3074,8 +3147,19 @@ public class AudioService extends IAudioService.Stub } int oldIndex = mStreamStates[streamType].getIndex(device); - if (adjustVolume - && (direction != AudioManager.ADJUST_SAME) && (keyEventMode != VOL_ADJUST_END)) { + // Check if the volume adjustment should be handled by an absolute volume controller instead + if (isAbsoluteVolumeDevice(device) + && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { + AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device); + if (info.mHandlesVolumeAdjustment) { + dispatchAbsoluteVolumeAdjusted(streamType, info, oldIndex, direction, + keyEventMode); + return; + } + } + + if (adjustVolume && (direction != AudioManager.ADJUST_SAME) + && (keyEventMode != AudioDeviceVolumeManager.ADJUST_MODE_END)) { mAudioHandler.removeMessages(MSG_UNMUTE_STREAM); if (isMuteAdjust && !mFullVolumeDevices.contains(device)) { @@ -3136,6 +3220,10 @@ public class AudioService extends IAudioService.Stub + newIndex + "stream=" + streamType); } mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10); + } else if (isAbsoluteVolumeDevice(device) + && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { + AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device); + dispatchAbsoluteVolumeChanged(streamType, info, newIndex); } if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET @@ -3201,14 +3289,14 @@ public class AudioService extends IAudioService.Stub final long ident = Binder.clearCallingIdentity(); try { switch (keyEventMode) { - case VOL_ADJUST_NORMAL: + case AudioDeviceVolumeManager.ADJUST_MODE_NORMAL: fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true); fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false); break; - case VOL_ADJUST_START: + case AudioDeviceVolumeManager.ADJUST_MODE_START: fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, true); break; - case VOL_ADJUST_END: + case AudioDeviceVolumeManager.ADJUST_MODE_END: fullVolumeHdmiClient.sendVolumeKeyEvent(keyCode, false); break; default: @@ -3794,6 +3882,11 @@ public class AudioService extends IAudioService.Stub + "stream=" + streamType); } mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10); + } else if (isAbsoluteVolumeDevice(device) + && ((flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0)) { + AbsoluteVolumeDeviceInfo info = mAbsoluteVolumeDeviceInfoMap.get(device); + + dispatchAbsoluteVolumeChanged(streamType, info, index); } if (device == AudioSystem.DEVICE_OUT_BLE_HEADSET @@ -3872,6 +3965,38 @@ public class AudioService extends IAudioService.Stub return AudioVolumeGroup.DEFAULT_VOLUME_GROUP; } + private void dispatchAbsoluteVolumeChanged(int streamType, AbsoluteVolumeDeviceInfo deviceInfo, + int index) { + VolumeInfo volumeInfo = deviceInfo.getMatchingVolumeInfoForStream(streamType); + if (volumeInfo != null) { + try { + deviceInfo.mCallback.dispatchDeviceVolumeChanged(deviceInfo.mDevice, + new VolumeInfo.Builder(volumeInfo) + .setVolumeIndex(rescaleIndex(index, streamType, volumeInfo)) + .build()); + } catch (RemoteException e) { + Log.w(TAG, "Couldn't dispatch absolute volume behavior volume change"); + } + } + } + + private void dispatchAbsoluteVolumeAdjusted(int streamType, + AbsoluteVolumeDeviceInfo deviceInfo, int index, int direction, int mode) { + VolumeInfo volumeInfo = deviceInfo.getMatchingVolumeInfoForStream(streamType); + if (volumeInfo != null) { + try { + deviceInfo.mCallback.dispatchDeviceVolumeAdjusted(deviceInfo.mDevice, + new VolumeInfo.Builder(volumeInfo) + .setVolumeIndex(rescaleIndex(index, streamType, volumeInfo)) + .build(), + direction, + mode); + } catch (RemoteException e) { + Log.w(TAG, "Couldn't dispatch absolute volume behavior volume adjustment"); + } + } + } + // No ringer or zen muted stream volumes can be changed unless it'll exit dnd private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) { @@ -4007,6 +4132,14 @@ public class AudioService extends IAudioService.Stub if (streamType == AudioSystem.STREAM_MUSIC) { flags = updateFlagsForTvPlatform(flags); + synchronized (mHdmiClientLock) { + // Don't display volume UI on a TV Playback device when using absolute volume + if (mHdmiCecVolumeControlEnabled && mHdmiPlaybackClient != null + && (isAbsoluteVolumeDevice(device) + || isA2dpAbsoluteVolumeDevice(device))) { + flags &= ~AudioManager.FLAG_SHOW_UI; + } + } if (isFullVolumeDevice(device)) { flags &= ~AudioManager.FLAG_SHOW_UI; } @@ -5183,7 +5316,8 @@ public class AudioService extends IAudioService.Stub // direction and stream type swap here because the public // adjustSuggested has a different order than the other methods. adjustSuggestedStreamVolume(direction, streamType, flags, packageName, packageName, - uid, pid, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL); + uid, pid, hasAudioSettingsPermission(uid, pid), + AudioDeviceVolumeManager.ADJUST_MODE_NORMAL); } /** @see AudioManager#adjustStreamVolumeForUid(int, int, int, String, int, int, int) */ @@ -5203,7 +5337,8 @@ public class AudioService extends IAudioService.Stub } adjustStreamVolume(streamType, direction, flags, packageName, packageName, uid, pid, - null, hasAudioSettingsPermission(uid, pid), VOL_ADJUST_NORMAL); + null, hasAudioSettingsPermission(uid, pid), + AudioDeviceVolumeManager.ADJUST_MODE_NORMAL); } /** @see AudioManager#setStreamVolumeForUid(int, int, int, String, int, int, int) */ @@ -6423,15 +6558,16 @@ public class AudioService extends IAudioService.Stub /** * @see AudioDeviceVolumeManager#setDeviceAbsoluteMultiVolumeBehavior - * @param cb - * @param attr - * @param volumes + * + * @param register Whether the listener is to be registered or unregistered. If false, the + * device adopts variable volume behavior. */ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.BLUETOOTH_PRIVILEGED }) public void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register, IAudioDeviceVolumeDispatcher cb, String packageName, - AudioDeviceAttributes device, List<VolumeInfo> volumes) { + AudioDeviceAttributes device, List<VolumeInfo> volumes, + boolean handlesVolumeAdjustment) { // verify permissions if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) != PackageManager.PERMISSION_GRANTED @@ -6444,12 +6580,44 @@ public class AudioService extends IAudioService.Stub Objects.requireNonNull(device); Objects.requireNonNull(volumes); - // current implementation maps this call to existing abs volume API of AudioManager - // TODO implement the volume/device listener through IAudioDeviceVolumeDispatcher - final int volumeBehavior = volumes.size() == 1 - ? AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE - : AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE; - setDeviceVolumeBehavior(device, volumeBehavior, packageName); + int deviceOut = device.getInternalType(); + if (register) { + AbsoluteVolumeDeviceInfo info = new AbsoluteVolumeDeviceInfo( + device, volumes, cb, handlesVolumeAdjustment); + boolean volumeBehaviorChanged = + removeAudioSystemDeviceOutFromFullVolumeDevices(deviceOut) + | removeAudioSystemDeviceOutFromFixedVolumeDevices(deviceOut) + | (addAudioSystemDeviceOutToAbsVolumeDevices(deviceOut, info) == null); + if (volumeBehaviorChanged) { + dispatchDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); + } + // Update stream volumes to the given device, if specified in a VolumeInfo. + // Mute state is not updated because it is stream-wide - the only way to mute a + // stream's output to a particular device is to set the volume index to zero. + for (VolumeInfo volumeInfo : volumes) { + if (volumeInfo.getVolumeIndex() != VolumeInfo.INDEX_NOT_SET + && volumeInfo.getMinVolumeIndex() != VolumeInfo.INDEX_NOT_SET + && volumeInfo.getMaxVolumeIndex() != VolumeInfo.INDEX_NOT_SET) { + if (volumeInfo.hasStreamType()) { + setStreamVolumeInt(volumeInfo.getStreamType(), + rescaleIndex(volumeInfo, volumeInfo.getStreamType()), + deviceOut, false /*force*/, packageName, + true /*hasModifyAudioSettings*/); + } else { + for (int streamType : volumeInfo.getVolumeGroup().getLegacyStreamTypes()) { + setStreamVolumeInt(streamType, rescaleIndex(volumeInfo, streamType), + deviceOut, false /*force*/, packageName, + true /*hasModifyAudioSettings*/); + } + } + } + } + } else { + boolean wasAbsVol = removeAudioSystemDeviceOutFromAbsVolumeDevices(deviceOut) != null; + if (wasAbsVol) { + dispatchDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE); + } + } } /** @@ -6486,17 +6654,23 @@ public class AudioService extends IAudioService.Stub case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE: volumeBehaviorChanged |= removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut) - | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut); + | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut) + | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) + != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED: volumeBehaviorChanged |= removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut) - | addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut); + | addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut) + | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) + != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL: volumeBehaviorChanged |= addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut) - | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut); + | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut) + | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) + != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE: @@ -6545,17 +6719,17 @@ public class AudioService extends IAudioService.Stub // setDeviceVolumeBehavior has not been explicitly called for the device type. Deduce the // current volume behavior. - if ((mFullVolumeDevices.contains(audioSystemDeviceOut))) { + if (mFullVolumeDevices.contains(audioSystemDeviceOut)) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL; } - if ((mFixedVolumeDevices.contains(audioSystemDeviceOut))) { + if (mFixedVolumeDevices.contains(audioSystemDeviceOut)) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED; } - if ((mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut))) { + if (mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut)) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE; } - if (audioSystemDeviceOut == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP - && mAvrcpAbsVolSupported) { + if (isAbsoluteVolumeDevice(audioSystemDeviceOut) + || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE; } return AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE; @@ -7320,8 +7494,7 @@ public class AudioService extends IAudioService.Stub int index; if (isFullyMuted()) { index = 0; - } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) - && mAvrcpAbsVolSupported) { + } else if (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)) { index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); } else if (isFullVolumeDevice(device)) { index = (mIndexMax + 5)/10; @@ -7342,8 +7515,8 @@ public class AudioService extends IAudioService.Stub if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (isFullyMuted()) { index = 0; - } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) - && mAvrcpAbsVolSupported) { + } else if (isAbsoluteVolumeDevice(device) + || isA2dpAbsoluteVolumeDevice(device)) { index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); } else if (isFullVolumeDevice(device)) { index = (mIndexMax + 5)/10; @@ -7762,8 +7935,9 @@ public class AudioService extends IAudioService.Stub // Make sure volume is also maxed out on A2DP device for aliased stream // that may have a different device selected int streamDevice = getDeviceForStream(streamType); - if ((device != streamDevice) && mAvrcpAbsVolSupported - && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) { + if ((device != streamDevice) + && (isAbsoluteVolumeDevice(device) + || isA2dpAbsoluteVolumeDevice(device))) { mStreamStates[streamType].applyDeviceVolume_syncVSS(device); } mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice); @@ -8153,7 +8327,7 @@ public class AudioService extends IAudioService.Stub updateMasterBalance(mContentResolver); updateEncodedSurroundOutput(); sendEnabledSurroundFormats(mContentResolver, mSurroundModeChanged); - updateAssistantUId(false); + updateAssistantUIdLocked(/* forceUpdate= */ false); } } @@ -9688,6 +9862,8 @@ public class AudioService extends IAudioService.Stub pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume); pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices)); pw.print(" mFullVolumeDevices="); pw.println(dumpDeviceTypes(mFullVolumeDevices)); + pw.print(" mAbsoluteVolumeDevices.keySet()="); pw.println(dumpDeviceTypes( + mAbsoluteVolumeDeviceInfoMap.keySet())); pw.print(" mExtVolumeController="); pw.println(mExtVolumeController); pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient); pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient); @@ -11489,6 +11665,23 @@ public class AudioService extends IAudioService.Stub return mFullVolumeDevices.contains(deviceType); } + /** + * Returns whether the input device uses absolute volume behavior. This is distinct + * from Bluetooth A2DP absolute volume behavior ({@link #isA2dpAbsoluteVolumeDevice}). + */ + private boolean isAbsoluteVolumeDevice(int deviceType) { + return mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType); + } + + /** + * Returns whether the input device is a Bluetooth A2dp device that uses absolute volume + * behavior. This is distinct from the general implementation of absolute volume behavior + * ({@link #isAbsoluteVolumeDevice}). + */ + private boolean isA2dpAbsoluteVolumeDevice(int deviceType) { + return mAvrcpAbsVolSupported && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(deviceType); + } + //==================== // Helper functions for {set,get}DeviceVolumeBehavior //==================== @@ -11581,6 +11774,24 @@ public class AudioService extends IAudioService.Stub return mFullVolumeDevices.remove(audioSystemDeviceOut); } + private AbsoluteVolumeDeviceInfo addAudioSystemDeviceOutToAbsVolumeDevices( + int audioSystemDeviceOut, AbsoluteVolumeDeviceInfo info) { + if (DEBUG_VOL) { + Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + + " from mAbsoluteVolumeDeviceInfoMap"); + } + return mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info); + } + + private AbsoluteVolumeDeviceInfo removeAudioSystemDeviceOutFromAbsVolumeDevices( + int audioSystemDeviceOut) { + if (DEBUG_VOL) { + Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + + " from mAbsoluteVolumeDeviceInfoMap"); + } + return mAbsoluteVolumeDeviceInfoMap.remove(audioSystemDeviceOut); + } + //==================== // Helper functions for app ops //==================== diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 49a935ebadc9..d10ed55281ef 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -104,7 +104,7 @@ public class BtHelper { // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall()) /*package*/ static final int SCO_MODE_VIRTUAL_CALL = 0; // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition()) - private static final int SCO_MODE_VR = 2; + private static final int SCO_MODE_VR = 2; // max valid SCO audio mode values private static final int SCO_MODE_MAX = 2; @@ -305,68 +305,76 @@ public class BtHelper { BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); setBtScoActiveDevice(btDevice); } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { - boolean broadcast = false; - int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); - Log.i(TAG, "receiveBtEvent ACTION_AUDIO_STATE_CHANGED: " + btState); - switch (btState) { - case BluetoothHeadset.STATE_AUDIO_CONNECTED: - scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; - if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL - && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) { - mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; - } else if (mDeviceBroker.isBluetoothScoRequested()) { - // broadcast intent if the connection was initated by AudioService - broadcast = true; - } - mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent"); - break; - case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: - mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent"); - scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; - // There are two cases where we want to immediately reconnect audio: - // 1) If a new start request was received while disconnecting: this was - // notified by requestScoState() setting state to SCO_STATE_ACTIVATE_REQ. - // 2) If audio was connected then disconnected via Bluetooth APIs and - // we still have pending activation requests by apps: this is indicated by - // state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested. - if (mScoAudioState == SCO_STATE_ACTIVATE_REQ - || (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL - && mDeviceBroker.isBluetoothScoRequested())) { - if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null - && connectBluetoothScoAudioHelper(mBluetoothHeadset, - mBluetoothHeadsetDevice, mScoAudioMode)) { - mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; - scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTING; - broadcast = true; - break; - } - } - if (mScoAudioState != SCO_STATE_ACTIVE_EXTERNAL) { + Log.i(TAG,"receiveBtEvent ACTION_AUDIO_STATE_CHANGED: "+btState); + mDeviceBroker.postScoAudioStateChanged(btState); + } + } + + /** + * Exclusively called from AudioDeviceBroker when handling MSG_I_SCO_AUDIO_STATE_CHANGED + * as part of the serialization of the communication route selection + */ + // @GuardedBy("AudioDeviceBroker.mSetModeLock") + @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + void onScoAudioStateChanged(int state) { + boolean broadcast = false; + int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; + switch (state) { + case BluetoothHeadset.STATE_AUDIO_CONNECTED: + scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; + if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL + && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) { + mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; + } else if (mDeviceBroker.isBluetoothScoRequested()) { + // broadcast intent if the connection was initated by AudioService + broadcast = true; + } + mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent"); + break; + case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: + mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent"); + scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; + // There are two cases where we want to immediately reconnect audio: + // 1) If a new start request was received while disconnecting: this was + // notified by requestScoState() setting state to SCO_STATE_ACTIVATE_REQ. + // 2) If audio was connected then disconnected via Bluetooth APIs and + // we still have pending activation requests by apps: this is indicated by + // state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested. + if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) { + if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null + && connectBluetoothScoAudioHelper(mBluetoothHeadset, + mBluetoothHeadsetDevice, mScoAudioMode)) { + mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; + scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTING; broadcast = true; + break; } - mScoAudioState = SCO_STATE_INACTIVE; - break; - case BluetoothHeadset.STATE_AUDIO_CONNECTING: - if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL - && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) { - mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; - } - break; - default: - break; - } - if (broadcast) { - broadcastScoConnectionState(scoAudioState); - //FIXME: this is to maintain compatibility with deprecated intent - // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. - Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); - newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); - sendStickyBroadcastToAll(newIntent); - } + } + if (mScoAudioState != SCO_STATE_ACTIVE_EXTERNAL) { + broadcast = true; + } + mScoAudioState = SCO_STATE_INACTIVE; + break; + case BluetoothHeadset.STATE_AUDIO_CONNECTING: + if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL + && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) { + mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; + } + break; + default: + break; + } + if(broadcast) { + broadcastScoConnectionState(scoAudioState); + //FIXME: this is to maintain compatibility with deprecated intent + // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. + Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); + newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); + sendStickyBroadcastToAll(newIntent); } - } + } /** * * @return false if SCO isn't connected @@ -756,6 +764,15 @@ public class BtHelper { case SCO_STATE_ACTIVE_INTERNAL: Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return"); break; + case SCO_STATE_ACTIVE_EXTERNAL: + /* Confirm SCO Audio connection to requesting app as it is already connected + * externally (i.e. through SCO APIs by Telecom service). + * Once SCO Audio is disconnected by the external owner, we will reconnect it + * automatically on behalf of the requesting app and the state will move to + * SCO_STATE_ACTIVE_INTERNAL. + */ + broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); + break; default: Log.w(TAG, "requestScoState: failed to connect in state " + mScoAudioState + ", scoAudioMode=" + scoAudioMode); diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 311fa7c16958..76d71e2b968a 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -131,7 +131,7 @@ abstract class DisplayDevice { * Only used for mirroring started from MediaProjection. */ @Nullable - public Point getDisplaySurfaceDefaultSize() { + public Point getDisplaySurfaceDefaultSizeLocked() { return null; } diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 064e307274b9..d12c6219b67f 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -30,9 +30,8 @@ import android.util.Slog; import android.util.Spline; import android.view.DisplayAddress; -import com.android.internal.annotations.VisibleForTesting; - import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.display.BrightnessSynchronizer; import com.android.server.display.config.BrightnessThresholds; import com.android.server.display.config.BrightnessThrottlingMap; @@ -296,9 +295,9 @@ public class DisplayDeviceConfig { * @return A configuration instance for the specified display. */ public static DisplayDeviceConfig create(Context context, long physicalDisplayId, - boolean isDefaultDisplay) { + boolean isFirstDisplay) { final DisplayDeviceConfig config = createWithoutDefaultValues(context, physicalDisplayId, - isDefaultDisplay); + isFirstDisplay); config.copyUninitializedValuesFromSecondaryConfig(loadDefaultConfigurationXml(context)); return config; @@ -323,7 +322,7 @@ public class DisplayDeviceConfig { } private static DisplayDeviceConfig createWithoutDefaultValues(Context context, - long physicalDisplayId, boolean isDefaultDisplay) { + long physicalDisplayId, boolean isFirstDisplay) { DisplayDeviceConfig config; config = loadConfigFromDirectory(context, Environment.getProductDirectory(), @@ -341,7 +340,7 @@ public class DisplayDeviceConfig { // If no config can be loaded from any ddc xml at all, // prepare a whole config using the global config.xml. // Guaranteed not null - return create(context, isDefaultDisplay); + return create(context, isFirstDisplay); } private static DisplayConfiguration loadDefaultConfigurationXml(Context context) { diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index a311ba1825b9..edaa18a88637 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -39,7 +39,7 @@ final class DisplayDeviceInfo { * Flag: Indicates that this display device should be considered the default display * device of the system. */ - public static final int FLAG_DEFAULT_DISPLAY = 1 << 0; + public static final int FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY = 1 << 0; /** * Flag: Indicates that the orientation of this display device is coupled to the @@ -538,8 +538,8 @@ final class DisplayDeviceInfo { private static String flagsToString(int flags) { StringBuilder msg = new StringBuilder(); - if ((flags & FLAG_DEFAULT_DISPLAY) != 0) { - msg.append(", FLAG_DEFAULT_DISPLAY"); + if ((flags & FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) { + msg.append(", FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY"); } if ((flags & FLAG_ROTATES_WITH_CONTENT) != 0) { msg.append(", FLAG_ROTATES_WITH_CONTENT"); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index e21edc9c4468..932717a4a39d 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -397,8 +397,7 @@ public final class DisplayManagerService extends SystemService { private final ArrayList<DisplayViewport> mTempViewports = new ArrayList<>(); // The default color mode for default displays. Overrides the usual - // Display.Display.COLOR_MODE_DEFAULT for displays with the - // DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY flag set. + // Display.Display.COLOR_MODE_DEFAULT for local displays. private final int mDefaultDisplayDefaultColorMode; // Lists of UIDs that are present on the displays. Maps displayId -> array of UIDs. @@ -1682,8 +1681,7 @@ public final class DisplayManagerService extends SystemService { if (display.getPrimaryDisplayDeviceLocked() == device) { int colorMode = mPersistentDataStore.getColorMode(device); if (colorMode == Display.COLOR_MODE_INVALID) { - if ((device.getDisplayDeviceInfoLocked().flags - & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) { + if (display.getDisplayIdLocked() == Display.DEFAULT_DISPLAY) { colorMode = mDefaultDisplayDefaultColorMode; } else { colorMode = Display.COLOR_MODE_DEFAULT; @@ -3880,8 +3878,8 @@ public final class DisplayManagerService extends SystemService { if (device == null) { return null; } + return device.getDisplaySurfaceDefaultSizeLocked(); } - return device.getDisplaySurfaceDefaultSize(); } @Override diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 540ae8165dbd..eaa1d4b098a1 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -141,9 +141,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { LocalDisplayDevice device = mDevices.get(physicalDisplayId); if (device == null) { // Display was added. - final boolean isDefaultDisplay = mDevices.size() == 0; + final boolean isFirstDisplay = mDevices.size() == 0; device = new LocalDisplayDevice(displayToken, physicalDisplayId, staticInfo, - dynamicInfo, modeSpecs, isDefaultDisplay); + dynamicInfo, modeSpecs, isFirstDisplay); mDevices.put(physicalDisplayId, device); sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); } else if (device.updateDisplayPropertiesLocked(staticInfo, dynamicInfo, @@ -187,7 +187,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>(); private final DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs = new DisplayModeDirector.DesiredDisplayModeSpecs(); - private final boolean mIsDefaultDisplay; + private final boolean mIsFirstDisplay; private final BacklightAdapter mBacklightAdapter; private final SidekickInternal mSidekickInternal; @@ -226,14 +226,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, SurfaceControl.StaticDisplayInfo staticDisplayInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, - SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isDefaultDisplay) { + SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isFirstDisplay) { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId, getContext()); mPhysicalDisplayId = physicalDisplayId; - mIsDefaultDisplay = isDefaultDisplay; + mIsFirstDisplay = isFirstDisplay; updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs); mSidekickInternal = LocalServices.getService(SidekickInternal.class); - mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay, + mBacklightAdapter = new BacklightAdapter(displayToken, isFirstDisplay, mSurfaceControlProxy); mActiveDisplayModeAtStartId = dynamicInfo.activeDisplayModeId; } @@ -480,7 +480,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { // Load display device config final Context context = getOverlayContext(); mDisplayDeviceConfig = DisplayDeviceConfig.create(context, mPhysicalDisplayId, - mIsDefaultDisplay); + mIsFirstDisplay); // Load brightness HWC quirk mBacklightAdapter.setForceSurfaceControl(mDisplayDeviceConfig.hasQuirk( @@ -652,9 +652,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { final Resources res = getOverlayContext().getResources(); - if (mIsDefaultDisplay) { - mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY; + mInfo.flags |= DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY; + if (mIsFirstDisplay) { if (res.getBoolean(com.android.internal.R.bool.config_mainBuiltInDisplayIsRound) || (Build.IS_EMULATOR && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) { @@ -1438,9 +1438,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { /** * @param displayToken Token for display associated with this backlight. - * @param isDefaultDisplay {@code true} if it is the default display. + * @param isFirstDisplay {@code true} if it is the first display. */ - BacklightAdapter(IBinder displayToken, boolean isDefaultDisplay, + BacklightAdapter(IBinder displayToken, boolean isFirstDisplay, SurfaceControlProxy surfaceControlProxy) { mDisplayToken = displayToken; mSurfaceControlProxy = surfaceControlProxy; @@ -1448,7 +1448,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mUseSurfaceControlBrightness = mSurfaceControlProxy .getDisplayBrightnessSupport(mDisplayToken); - if (!mUseSurfaceControlBrightness && isDefaultDisplay) { + if (!mUseSurfaceControlBrightness && isFirstDisplay) { LightsManager lights = LocalServices.getService(LightsManager.class); mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT); } else { diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index add0a9f77108..70c9e23c6af8 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -16,6 +16,8 @@ package com.android.server.display; +import static android.view.Display.DEFAULT_DISPLAY; + import android.annotation.NonNull; import android.content.Context; import android.hardware.devicestate.DeviceStateManager; @@ -204,6 +206,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { if (DEBUG) { Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked()); } + handleDisplayDeviceRemovedLocked(device); updateLogicalDisplaysLocked(); break; } @@ -529,12 +532,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private void handleDisplayDeviceAddedLocked(DisplayDevice device) { DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); - // Internal Displays need to have additional initialization. - // This initializes a default dynamic display layout for INTERNAL - // devices, which is used as a fallback in case no static layout definitions + // The default Display needs to have additional initialization. + // This initializes a default dynamic display layout for the default + // device, which is used as a fallback in case no static layout definitions // exist or cannot be loaded. - if (deviceInfo.type == Display.TYPE_INTERNAL) { - initializeInternalDisplayDeviceLocked(device); + if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) { + initializeDefaultDisplayDeviceLocked(device); } // Create a logical display for the new display device @@ -545,6 +548,38 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { updateLogicalDisplaysLocked(); } + private void handleDisplayDeviceRemovedLocked(DisplayDevice device) { + final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); + Layout.Display layoutDisplay = layout.getById(DEFAULT_DISPLAY); + if (layoutDisplay == null) { + return; + } + DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked(); + + if (layoutDisplay.getAddress().equals(deviceInfo.address)) { + layout.removeDisplayLocked(DEFAULT_DISPLAY); + + // Need to find another local display and make it default + for (int i = 0; i < mLogicalDisplays.size(); i++) { + LogicalDisplay nextDisplay = mLogicalDisplays.valueAt(i); + DisplayDevice nextDevice = nextDisplay.getPrimaryDisplayDeviceLocked(); + if (nextDevice == null) { + continue; + } + DisplayDeviceInfo nextDeviceInfo = nextDevice.getDisplayDeviceInfoLocked(); + + if ((nextDeviceInfo.flags + & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0 + && !nextDeviceInfo.address.equals(deviceInfo.address)) { + layout.createDisplayLocked(nextDeviceInfo.address, + /* isDefault= */ true, /* isEnabled= */ true); + applyLayoutLocked(); + return; + } + } + } + } + /** * Updates the rest of the display system once all the changes are applied for display * devices and logical displays. The includes releasing invalid/empty LogicalDisplays, @@ -900,16 +935,18 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { return isOwnDisplayGroup ? mNextNonDefaultGroupId++ : Display.DEFAULT_DISPLAY_GROUP; } - private void initializeInternalDisplayDeviceLocked(DisplayDevice device) { + private void initializeDefaultDisplayDeviceLocked(DisplayDevice device) { // We always want to make sure that our default layout creates a logical - // display for every internal display device that is found. - // To that end, when we are notified of a new internal display, we add it to + // display for the default display device that is found. + // To that end, when we are notified of a new default display, we add it to // the default layout definition if it is not already there. final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); + if (layout.getById(DEFAULT_DISPLAY) != null) { + // The layout should only have one default display + return; + } final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); - final boolean isDefault = (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0; - final boolean isEnabled = isDefault || mSupportsConcurrentInternalDisplays; - layout.createDisplayLocked(info.address, isDefault, isEnabled); + layout.createDisplayLocked(info.address, /* isDefault= */ true, /* isEnabled= */ true); } private int assignLayerStackLocked(int displayId) { diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index ea313743d28d..dde8831090df 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -302,7 +302,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { } @Override - public Point getDisplaySurfaceDefaultSize() { + public Point getDisplaySurfaceDefaultSizeLocked() { if (mSurface == null) { return null; } diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java index e53aec12f186..7e16ea8b3ace 100644 --- a/services/core/java/com/android/server/display/layout/Layout.java +++ b/services/core/java/com/android/server/display/layout/Layout.java @@ -67,7 +67,7 @@ public class Layout { // See if we're dealing with the "default" display if (isDefault && getById(DEFAULT_DISPLAY) != null) { Slog.w(TAG, "Ignoring attempt to add a second default display: " + address); - isDefault = false; + return null; } // Assign a logical display ID and create the new display. @@ -75,10 +75,20 @@ public class Layout { // different layouts, a logical display can be destroyed and later recreated with the // same logical display ID. final int logicalDisplayId = assignDisplayIdLocked(isDefault); - final Display layout = new Display(address, logicalDisplayId, isEnabled); + final Display display = new Display(address, logicalDisplayId, isEnabled); + + mDisplays.add(display); + return display; + } - mDisplays.add(layout); - return layout; + /** + * @param id The ID of the display to remove. + */ + public void removeDisplayLocked(int id) { + Display display = getById(id); + if (display != null) { + mDisplays.remove(display); + } } /** diff --git a/services/core/java/com/android/server/hdmi/GiveFeaturesAction.java b/services/core/java/com/android/server/hdmi/GiveFeaturesAction.java deleted file mode 100644 index 45425657c0f6..000000000000 --- a/services/core/java/com/android/server/hdmi/GiveFeaturesAction.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.hdmi; - -import android.hardware.hdmi.HdmiControlManager; -import android.hardware.hdmi.IHdmiControlCallback; -import android.hardware.tv.cec.V1_0.SendMessageResult; - -/** - * Sends <Give Features> to a target device. This action succeeds if the device responds with - * <Report Features> within {@link HdmiConfig.TIMEOUT_MS}. - * - * This action does not update the CEC network directly; an incoming <Report Features> message - * should be handled separately by {@link HdmiCecNetwork}. - */ -public class GiveFeaturesAction extends HdmiCecFeatureAction { - private static final String TAG = "GiveFeaturesAction"; - - private static final int STATE_WAITING_FOR_REPORT_FEATURES = 1; - - private final int mTargetAddress; - - public GiveFeaturesAction(HdmiCecLocalDevice source, int targetAddress, - IHdmiControlCallback callback) { - super(source, callback); - - mTargetAddress = targetAddress; - } - - boolean start() { - sendCommand(HdmiCecMessageBuilder.buildGiveFeatures(getSourceAddress(), mTargetAddress), - result -> { - if (result == SendMessageResult.SUCCESS) { - mState = STATE_WAITING_FOR_REPORT_FEATURES; - addTimer(STATE_WAITING_FOR_REPORT_FEATURES, HdmiConfig.TIMEOUT_MS); - } else { - finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); - } - }); - return true; - } - - boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAITING_FOR_REPORT_FEATURES) { - return false; - } - if (cmd instanceof ReportFeaturesMessage) { - return handleReportFeatures((ReportFeaturesMessage) cmd); - } - return false; - } - - private boolean handleReportFeatures(ReportFeaturesMessage cmd) { - if (cmd.getSource() == mTargetAddress) { - // No need to update the network, since it should already have processed this message. - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); - return true; - } - return false; - } - - void handleTimerEvent(int state) { - finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); - } -} diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java index 64971746dce9..185eaa92d511 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java @@ -19,6 +19,7 @@ package com.android.server.hdmi; import static com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import android.annotation.Nullable; +import android.hardware.hdmi.DeviceFeatures; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; @@ -512,6 +513,9 @@ public class HdmiCecNetwork { } switch (message.getOpcode()) { + case Constants.MESSAGE_FEATURE_ABORT: + handleFeatureAbort(message); + break; case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS: handleReportPhysicalAddress(message); break; @@ -544,6 +548,38 @@ public class HdmiCecNetwork { } @ServiceThreadOnly + private void handleFeatureAbort(HdmiCecMessage message) { + assertRunOnServiceThread(); + + if (message.getParams().length < 2) { + return; + } + + int originalOpcode = message.getParams()[0] & 0xFF; + int reason = message.getParams()[1] & 0xFF; + + // Check if we received <Feature Abort> in response to <Set Audio Volume Level>. + // This provides information on whether the source supports the message. + if (originalOpcode == Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL) { + + @DeviceFeatures.FeatureSupportStatus int featureSupport = + reason == Constants.ABORT_UNRECOGNIZED_OPCODE + ? DeviceFeatures.FEATURE_NOT_SUPPORTED + : DeviceFeatures.FEATURE_SUPPORT_UNKNOWN; + + HdmiDeviceInfo currentDeviceInfo = getCecDeviceInfo(message.getSource()); + HdmiDeviceInfo newDeviceInfo = currentDeviceInfo.toBuilder() + .updateDeviceFeatures( + currentDeviceInfo.getDeviceFeatures().toBuilder() + .setSetAudioVolumeLevelSupport(featureSupport) + .build() + ) + .build(); + updateCecDevice(newDeviceInfo); + } + } + + @ServiceThreadOnly private void handleCecVersion(HdmiCecMessage message) { assertRunOnServiceThread(); diff --git a/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java b/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java index 5154669a90ab..96fd003c72b4 100644 --- a/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java +++ b/services/core/java/com/android/server/hdmi/SetAudioVolumeLevelDiscoveryAction.java @@ -16,7 +16,6 @@ package com.android.server.hdmi; -import static android.hardware.hdmi.DeviceFeatures.FEATURE_NOT_SUPPORTED; import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORTED; import static com.android.server.hdmi.Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL; @@ -78,13 +77,13 @@ public class SetAudioVolumeLevelDiscoveryAction extends HdmiCecFeatureAction { } private boolean handleFeatureAbort(HdmiCecMessage cmd) { + if (cmd.getParams().length < 2) { + return false; + } int originalOpcode = cmd.getParams()[0] & 0xFF; if (originalOpcode == MESSAGE_SET_AUDIO_VOLUME_LEVEL && cmd.getSource() == mTargetAddress) { - if (updateAvcSupport(FEATURE_NOT_SUPPORTED)) { - finishWithCallback(HdmiControlManager.RESULT_SUCCESS); - } else { - finishWithCallback(HdmiControlManager.RESULT_EXCEPTION); - } + // No need to update the network, since it should already have processed this message. + finishWithCallback(HdmiControlManager.RESULT_SUCCESS); return true; } return false; @@ -107,7 +106,7 @@ public class SetAudioVolumeLevelDiscoveryAction extends HdmiCecFeatureAction { */ private boolean updateAvcSupport( @DeviceFeatures.FeatureSupportStatus int setAudioVolumeLevelSupport) { - HdmiCecNetwork network = source().mService.getHdmiCecNetwork(); + HdmiCecNetwork network = localDevice().mService.getHdmiCecNetwork(); HdmiDeviceInfo currentDeviceInfo = network.getCecDeviceInfo(mTargetAddress); if (currentDeviceInfo == null) { diff --git a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java index 1ae7ac07594b..df612e63927f 100644 --- a/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java +++ b/services/core/java/com/android/server/media/metrics/MediaMetricsManagerService.java @@ -19,6 +19,7 @@ package com.android.server.media.metrics; import android.content.Context; import android.content.pm.PackageManager; import android.media.MediaMetrics; +import android.media.metrics.BundleSession; import android.media.metrics.IMediaMetricsManager; import android.media.metrics.NetworkEvent; import android.media.metrics.PlaybackErrorEvent; @@ -187,11 +188,33 @@ public final class MediaMetricsManagerService extends SystemService { return; } - int atomid = metrics.getInt("KEY_STATSD_ATOM_NUMBER"); + int atomid = metrics.getInt(BundleSession.KEY_STATSD_ATOM); switch (atomid) { default: return; // to be extended as we define statsd atoms + case 322: // MediaPlaybackStateEvent + // pattern for the keys: + // <statsd event> - <fieldname> + // match types to what stats will want + String _sessionId = metrics.getString("playbackstateevent-sessionid"); + int _state = metrics.getInt("playbackstateevent-state", -1); + long _lifetime = metrics.getLong("playbackstateevent-lifetime", -1); + if (_sessionId == null || _state < 0 || _lifetime < 0) { + Slog.d(TAG, "dropping incomplete data for atom 322: _sessionId: " + + _sessionId + " _state: " + _state + + " _lifetime: " + _lifetime); + return; + } + StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(322) + .writeString(_sessionId) + .writeInt(_state) + .writeLong(_lifetime) + .usePooledBuffer() + .build(); + StatsLog.write(statsEvent); + return; } } @@ -227,6 +250,13 @@ public final class MediaMetricsManagerService extends SystemService { } @Override + public void releaseSessionId(String sessionId, int userId) { + // De-authorize this session-id in the native mediametrics service. + // TODO: plumbing to the native mediametrics service + Slog.v(TAG, "Releasing sessionId " + sessionId + " for userId " + userId + " [NOP]"); + } + + @Override public String getPlaybackSessionId(int userId) { return getSessionIdInternal(userId); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 589b8f18b1a5..953b6aed9a82 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -26,6 +26,8 @@ import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.OBSERVE_NETWORK_POLICY; import static android.Manifest.permission.READ_PHONE_STATE; import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; +import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; +import static android.app.ActivityManager.isProcStateConsideredInteraction; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static android.content.Intent.ACTION_PACKAGE_ADDED; @@ -4042,14 +4044,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState) != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState); if (allowedWhileIdleOrPowerSaveModeChanged) { - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, procState); if (mDeviceIdleMode) { updateRuleForDeviceIdleUL(uid); } if (mRestrictPower) { updateRuleForRestrictPowerUL(uid); } - updateRulesForPowerRestrictionsUL(uid); + updateRulesForPowerRestrictionsUL(uid, procState); } if (mLowPowerStandbyActive) { boolean allowedInLpsChanged = @@ -4057,7 +4059,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { != isProcStateAllowedWhileInLowPowerStandby(newUidState); if (allowedInLpsChanged) { if (!allowedWhileIdleOrPowerSaveModeChanged) { - updateRulesForPowerRestrictionsUL(uid); + updateRulesForPowerRestrictionsUL(uid, procState); } updateRuleForLowPowerStandbyUL(uid); } @@ -4426,7 +4428,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @GuardedBy("mUidRulesFirstLock") - void updateRuleForAppIdleUL(int uid) { + void updateRuleForAppIdleUL(int uid, int uidProcessState) { if (!isUidValidForDenylistRulesUL(uid)) return; if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { @@ -4434,7 +4436,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } try { int appId = UserHandle.getAppId(uid); - if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid) + if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid, uidProcessState) && !isUidForegroundOnRestrictPowerUL(uid)) { setUidFirewallRuleUL(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY); if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL DENY " + uid); @@ -4585,7 +4587,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final UserInfo user = users.get(i); int uid = UserHandle.getUid(user.id, appId); // Update external firewall rules. - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRuleForDeviceIdleUL(uid); updateRuleForRestrictPowerUL(uid); // Update internal rules. @@ -4633,7 +4635,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } else { mAppIdleTempWhitelistAppIds.delete(uid); } - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRulesForPowerRestrictionsUL(uid); } finally { Binder.restoreCallingIdentity(token); @@ -4659,7 +4661,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Returns if the UID is currently considered idle. */ @VisibleForTesting boolean isUidIdle(int uid) { + return isUidIdle(uid, PROCESS_STATE_UNKNOWN); + } + + private boolean isUidIdle(int uid, int uidProcessState) { synchronized (mUidRulesFirstLock) { + if (uidProcessState != PROCESS_STATE_UNKNOWN && isProcStateConsideredInteraction( + uidProcessState)) { + return false; + } if (mAppIdleTempWhitelistAppIds.get(uid)) { // UID is temporarily allowlisted. return false; @@ -4746,7 +4756,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateRestrictionRulesForUidUL(int uid) { // Methods below only changes the firewall rules for the power-related modes. updateRuleForDeviceIdleUL(uid); - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRuleForRestrictPowerUL(uid); // If the uid has the necessary permissions, then it should be added to the restricted mode @@ -4920,7 +4930,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ @GuardedBy("mUidRulesFirstLock") private void updateRulesForPowerRestrictionsUL(int uid) { - updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid)); + updateRulesForPowerRestrictionsUL(uid, PROCESS_STATE_UNKNOWN); + } + + @GuardedBy("mUidRulesFirstLock") + private void updateRulesForPowerRestrictionsUL(int uid, int uidProcState) { + updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid, uidProcState)); } /** @@ -5028,7 +5043,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); synchronized (mUidRulesFirstLock) { mLogger.appIdleStateChanged(uid, idle); - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRulesForPowerRestrictionsUL(uid); } } catch (NameNotFoundException nnfe) { diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java index 4f2680904fae..273afcc9f769 100644 --- a/services/core/java/com/android/server/notification/GroupHelper.java +++ b/services/core/java/com/android/server/notification/GroupHelper.java @@ -42,7 +42,7 @@ public class GroupHelper { private final int mAutoGroupAtCount; // count the number of ongoing notifications per group - // userId -> (package name -> (group Id -> (set of notification keys))) + // userId|packageName -> (set of ongoing notifications that aren't in an app group) final ArrayMap<String, ArraySet<String>> mOngoingGroupCount = new ArrayMap<>(); @@ -55,52 +55,43 @@ public class GroupHelper { mCallback = callback; } - private String generatePackageGroupKey(int userId, String pkg, String group) { - return userId + "|" + pkg + "|" + group; + private String generatePackageKey(int userId, String pkg) { + return userId + "|" + pkg; } @VisibleForTesting - protected int getOngoingGroupCount(int userId, String pkg, String group) { - String key = generatePackageGroupKey(userId, pkg, group); + protected int getOngoingGroupCount(int userId, String pkg) { + String key = generatePackageKey(userId, pkg); return mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0)).size(); } - private void addToOngoingGroupCount(StatusBarNotification sbn, boolean add) { - if (sbn.getNotification().isGroupSummary()) return; - if (!sbn.isOngoing() && add) return; - String group = sbn.getGroup(); - if (group == null) return; - int userId = sbn.getUser().getIdentifier(); - String key = generatePackageGroupKey(userId, sbn.getPackageName(), group); + private void updateOngoingGroupCount(StatusBarNotification sbn, boolean add) { + if (sbn.getNotification().isGroupSummary()) { + return; + } + String key = generatePackageKey(sbn.getUserId(), sbn.getPackageName()); ArraySet<String> notifications = mOngoingGroupCount.getOrDefault(key, new ArraySet<>(0)); if (add) { notifications.add(sbn.getKey()); mOngoingGroupCount.put(key, notifications); } else { notifications.remove(sbn.getKey()); - // we dont need to put it back if it is default + // we don't need to put it back if it is default } - String combinedKey = generatePackageGroupKey(userId, sbn.getPackageName(), group); + boolean needsOngoingFlag = notifications.size() > 0; - mCallback.updateAutogroupSummary(userId, sbn.getPackageName(), needsOngoingFlag); + mCallback.updateAutogroupSummary(sbn.getUserId(), sbn.getPackageName(), needsOngoingFlag); } - public void onNotificationUpdated(StatusBarNotification childSbn, - boolean autogroupSummaryExists) { - if (childSbn.getGroup() != AUTOGROUP_KEY - || childSbn.getNotification().isGroupSummary()) return; - if (childSbn.isOngoing()) { - addToOngoingGroupCount(childSbn, true); - } else { - addToOngoingGroupCount(childSbn, false); - } + public void onNotificationUpdated(StatusBarNotification childSbn) { + updateOngoingGroupCount(childSbn, childSbn.isOngoing() && !childSbn.isAppGroup()); } public void onNotificationPosted(StatusBarNotification sbn, boolean autogroupSummaryExists) { - if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey()); try { + updateOngoingGroupCount(sbn, sbn.isOngoing() && !sbn.isAppGroup()); + List<String> notificationsToGroup = new ArrayList<>(); - if (autogroupSummaryExists) addToOngoingGroupCount(sbn, true); if (!sbn.isAppGroup()) { // Not grouped by the app, add to the list of notifications for the app; // send grouping update if app exceeds the autogrouping limit. @@ -134,6 +125,7 @@ public class GroupHelper { // Grouped, but not by us. Send updates to un-autogroup, if we grouped it. maybeUngroup(sbn, false, sbn.getUserId()); } + } catch (Exception e) { Slog.e(TAG, "Failure processing new notification", e); } @@ -141,7 +133,7 @@ public class GroupHelper { public void onNotificationRemoved(StatusBarNotification sbn) { try { - addToOngoingGroupCount(sbn, false); + updateOngoingGroupCount(sbn, false); maybeUngroup(sbn, true, sbn.getUserId()); } catch (Exception e) { Slog.e(TAG, "Error processing canceled notification", e); @@ -189,7 +181,8 @@ public class GroupHelper { private void adjustAutogroupingSummary(int userId, String packageName, String triggeringKey, boolean summaryNeeded) { if (summaryNeeded) { - mCallback.addAutoGroupSummary(userId, packageName, triggeringKey); + mCallback.addAutoGroupSummary(userId, packageName, triggeringKey, + getOngoingGroupCount(userId, packageName) > 0); } else { mCallback.removeAutoGroupSummary(userId, packageName); } @@ -209,7 +202,8 @@ public class GroupHelper { protected interface Callback { void addAutoGroup(String key); void removeAutoGroup(String key); - void addAutoGroupSummary(int userId, String pkg, String triggeringKey); + void addAutoGroupSummary(int userId, String pkg, String triggeringKey, + boolean needsOngoingFlag); void removeAutoGroupSummary(int user, String pkg); void updateAutogroupSummary(int userId, String pkg, boolean needsOngoingFlag); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1885b5596e3e..326a5f2582e1 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2557,8 +2557,10 @@ public class NotificationManagerService extends SystemService { } @Override - public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) { - NotificationRecord r = createAutoGroupSummary(userId, pkg, triggeringKey); + public void addAutoGroupSummary(int userId, String pkg, String triggeringKey, + boolean needsOngoingFlag) { + NotificationRecord r = createAutoGroupSummary( + userId, pkg, triggeringKey, needsOngoingFlag); if (r != null) { final boolean isAppForeground = mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; @@ -5739,6 +5741,7 @@ public class NotificationManagerService extends SystemService { void removeAutogroupKeyLocked(String key) { NotificationRecord r = mNotificationsByKey.get(key); if (r == null) { + Slog.w(TAG, "Failed to remove autogroup " + key); return; } if (r.getSbn().getOverrideGroupKey() != null) { @@ -5778,7 +5781,8 @@ public class NotificationManagerService extends SystemService { } // Creates a 'fake' summary for a package that has exceeded the solo-notification limit. - NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey) { + NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey, + boolean needsOngoingFlag) { NotificationRecord summaryRecord = null; boolean isPermissionFixed = mPermissionHelper.isMigrationEnabled() ? mPermissionHelper.isPermissionFixed(pkg, userId) : false; @@ -5818,6 +5822,7 @@ public class NotificationManagerService extends SystemService { .setGroup(GroupHelper.AUTOGROUP_KEY) .setFlag(FLAG_AUTOGROUP_SUMMARY, true) .setFlag(Notification.FLAG_GROUP_SUMMARY, true) + .setFlag(FLAG_ONGOING_EVENT, needsOngoingFlag) .setColor(adjustedSbn.getNotification().color) .setLocalOnly(true) .build(); @@ -7356,17 +7361,16 @@ public class NotificationManagerService extends SystemService { mListeners.notifyPostedLocked(r, old); if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) && !isCritical(r)) { - mHandler.post(new Runnable() { - @Override - public void run() { + mHandler.post(() -> { + synchronized (mNotificationLock) { mGroupHelper.onNotificationPosted( n, hasAutoGroupSummaryLocked(n)); } }); } else if (oldSbn != null) { final NotificationRecord finalRecord = r; - mHandler.post(() -> mGroupHelper.onNotificationUpdated( - finalRecord.getSbn(), hasAutoGroupSummaryLocked(n))); + mHandler.post(() -> + mGroupHelper.onNotificationUpdated(finalRecord.getSbn())); } } else { Slog.e(TAG, "Not posting notification without small icon: " + notification); @@ -10429,10 +10433,10 @@ public class NotificationManagerService extends SystemService { boolean isPrimary, boolean enabled, boolean userSet) { super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet); - getContext().sendBroadcastAsUser( + mContext.sendBroadcastAsUser( new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED) .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), - UserHandle.ALL, null); + UserHandle.of(userId), null); } @Override diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 7b2dc28a396f..152c74553d32 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -1330,7 +1330,9 @@ public class AppsFilter implements Watchable, Snappable { + callingUid + " -> " + targetUid); return true; } - return mShouldFilterCache.valueAt(callingIndex, targetIndex); + if (!mShouldFilterCache.valueAt(callingIndex, targetIndex)) { + return false; + } } else { if (!shouldFilterApplicationInternal( callingUid, callingSetting, targetPkgSetting, userId)) { diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java index a3134a045d58..cac93236f411 100644 --- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java +++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java @@ -246,7 +246,7 @@ public class DefaultCrossProfileIntentFiltersUtils { private static final DefaultCrossProfileIntentFilter MEDIA_CAPTURE = new DefaultCrossProfileIntentFilter.Builder( DefaultCrossProfileIntentFilter.Direction.TO_PARENT, - /* flags= */0, + /* flags= */ ONLY_IF_NO_MATCH_FOUND, /* letsPersonalDataIntoProfile= */ true) .addAction(MediaStore.ACTION_IMAGE_CAPTURE) .addAction(MediaStore.ACTION_IMAGE_CAPTURE_SECURE) diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java index 0e1c1ad4120f..dc4dd12b3a18 100644 --- a/services/core/java/com/android/server/pm/DeletePackageHelper.java +++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java @@ -43,6 +43,7 @@ import android.content.pm.PackageChangeEvent; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.SharedLibraryInfo; +import android.content.pm.UserInfo; import android.content.pm.VersionedPackage; import android.net.Uri; import android.os.Binder; @@ -161,6 +162,15 @@ final class DeletePackageHelper { return PackageManager.DELETE_FAILED_INTERNAL_ERROR; } + if (PackageManagerServiceUtils.isSystemApp(uninstalledPs)) { + UserInfo userInfo = mUserManagerInternal.getUserInfo(userId); + if (userInfo == null || !userInfo.isAdmin()) { + Slog.w(TAG, "Not removing package " + packageName + + " as only admin user may downgrade system apps"); + return PackageManager.DELETE_FAILED_USER_RESTRICTED; + } + } + disabledSystemPs = mPm.mSettings.getDisabledSystemPkgLPr(packageName); // Static shared libs can be declared by any package, so let us not // allow removing a package if it provides a lib others depend on. diff --git a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java index 0ee07b650cf5..5597c9af7362 100644 --- a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java +++ b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java @@ -21,14 +21,11 @@ import static com.android.server.wm.ActivityInterceptorCallback.INTENT_RESOLVER_ import android.Manifest; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.app.ActivityTaskManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; -import android.os.RemoteException; import android.provider.DeviceConfig; -import android.util.Slog; import com.android.internal.R; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; @@ -39,10 +36,8 @@ import com.android.server.wm.ActivityTaskManagerInternal; /** * Service to register an {@code ActivityInterceptorCallback} that modifies any {@code Intent} - * that's being used to launch a user-space {@code ChooserActivity}, by adding - * EXTRA_PERMISSION_TOKEN, a Binder representing a single-use-only permission to invoke the - * #startActivityAsCaller() API (which normally isn't available in user-space); and setting the - * destination component to the delegated component when appropriate. + * that's being used to launch a user-space {@code ChooserActivity} by setting the destination + * component to the delegated component when appropriate. */ public final class IntentResolverInterceptor { private static final String TAG = "IntentResolverIntercept"; @@ -92,7 +87,6 @@ public final class IntentResolverInterceptor { private Intent modifyChooserIntent(Intent intent) { intent.setComponent(getUnbundledChooserComponentName()); - addStartActivityPermissionTokenToIntent(intent, getUnbundledChooserComponentName()); return intent; } @@ -103,18 +97,6 @@ public final class IntentResolverInterceptor { || targetComponent.equals(getUnbundledChooserComponentName()); } - private static Intent addStartActivityPermissionTokenToIntent( - Intent intent, ComponentName grantee) { - try { - intent.putExtra( - ActivityTaskManager.EXTRA_PERMISSION_TOKEN, - ActivityTaskManager.getService().requestStartActivityPermissionToken(grantee)); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to add permission token to chooser intent"); - } - return intent; - } - private static ComponentName getSystemChooserComponentName() { return new ComponentName("android", "com.android.internal.app.ChooserActivity"); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 5ba4cc115c21..1efaa735a56c 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -272,7 +272,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** * The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link - * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#Q} before getting the + * #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#R} before getting the * target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared * result will not trigger any user action in * {@link #checkUserActionRequirement(PackageInstallerSession)}. @@ -2083,7 +2083,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (validatedTargetSdk != INVALID_TARGET_SDK_VERSION - && validatedTargetSdk < Build.VERSION_CODES.Q) { + && validatedTargetSdk < Build.VERSION_CODES.R) { session.sendPendingUserActionIntent(target); return true; } diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index b2b59f194104..9ce4cdf840fd 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -338,7 +338,7 @@ class ShortcutPackage extends ShortcutPackageItem { public void ensureAllShortcutsVisibleToLauncher(@NonNull List<ShortcutInfo> shortcuts) { for (ShortcutInfo shortcut : shortcuts) { - if (!shortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER)) { + if (shortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER)) { throw new IllegalArgumentException("Shortcut ID=" + shortcut.getId() + " is hidden from launcher and may not be manipulated via APIs"); } @@ -399,7 +399,7 @@ class ShortcutPackage extends ShortcutPackageItem { & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL)); } - if (!newShortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER)) { + if (newShortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER)) { if (isAppSearchEnabled()) { synchronized (mLock) { mTransientShortcuts.put(newShortcut.getId(), newShortcut); @@ -477,7 +477,7 @@ class ShortcutPackage extends ShortcutPackageItem { & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL)); } - if (!newShortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER)) { + if (newShortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER)) { if (isAppSearchEnabled()) { synchronized (mLock) { mTransientShortcuts.put(newShortcut.getId(), newShortcut); diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 25fe0007ec4b..9ca4f247891d 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -2228,7 +2228,7 @@ public class ShortcutService extends IShortcutService.Stub { Objects.requireNonNull(shortcut); Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); Preconditions.checkArgument( - shortcut.isIncludedIn(ShortcutInfo.SURFACE_LAUNCHER), + !shortcut.isExcludedFromSurfaces(ShortcutInfo.SURFACE_LAUNCHER), "Shortcut excluded from launcher cannot be pinned"); ret.complete(String.valueOf(requestPinItem( packageName, userId, shortcut, null, null, resultIntent))); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 048f8d6a04fa..c04d6082877a 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -40,12 +40,14 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.app.AppOpsManager; import android.app.SynchronousUserSwitchObserver; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; @@ -1454,6 +1456,15 @@ public final class PowerManagerService extends SystemService private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag, String packageName, WorkSource ws, String historyTag, int uid, int pid, @Nullable IWakeLockCallback callback) { + + boolean isCallerPrivileged = false; + try { + ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(packageName, + PackageManager.ApplicationInfoFlags.of(0)); + isCallerPrivileged = appInfo.uid == uid && appInfo.isPrivilegedApp(); + } catch (PackageManager.NameNotFoundException e) { + // assume app is not privileged + } synchronized (mLock) { if (displayId != Display.INVALID_DISPLAY) { final DisplayInfo displayInfo = @@ -1500,7 +1511,7 @@ public final class PowerManagerService extends SystemService notifyAcquire = true; } - applyWakeLockFlagsOnAcquireLocked(wakeLock, uid); + applyWakeLockFlagsOnAcquireLocked(wakeLock, isCallerPrivileged); mDirty |= DIRTY_WAKE_LOCKS; updatePowerStateLocked(); if (notifyAcquire) { @@ -1539,8 +1550,34 @@ public final class PowerManagerService extends SystemService return null; } + private boolean isAcquireCausesWakeupFlagAllowed(String opPackageName, int opUid, + boolean isCallerPrivileged) { + if (opPackageName == null) { + return false; + } + if (isCallerPrivileged) { + if (DEBUG_SPEW) { + Slog.d(TAG, "Allowing device wake-up for privileged app, call attributed to " + + opPackageName); + } + return true; + } + if (mContext.getSystemService(AppOpsManager.class).checkOpNoThrow( + AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName) + == AppOpsManager.MODE_ALLOWED) { + if (DEBUG_SPEW) { + Slog.d(TAG, "Allowing device wake-up for app with special access " + opPackageName); + } + return true; + } + if (DEBUG_SPEW) { + Slog.d(TAG, "Not allowing device wake-up for " + opPackageName); + } + return false; + } + @GuardedBy("mLock") - private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) { + private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, boolean isCallerPrivileged) { if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0 && isScreenLock(wakeLock)) { String opPackageName; @@ -1560,10 +1597,30 @@ public final class PowerManagerService extends SystemService opPackageName = wakeLock.mPackageName; opUid = wakeLock.mOwnerUid; } - for (int idx = 0; idx < mPowerGroups.size(); idx++) { - wakePowerGroupLocked(mPowerGroups.valueAt(idx), mClock.uptimeMillis(), - PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag, opUid, opPackageName, - opUid); + Integer powerGroupId = wakeLock.getPowerGroupId(); + // powerGroupId is null if the wakelock associated display is no longer available + if (powerGroupId != null && isAcquireCausesWakeupFlagAllowed(opPackageName, opUid, + isCallerPrivileged)) { + if (powerGroupId == Display.INVALID_DISPLAY_GROUP) { + // wake up all display groups + if (DEBUG_SPEW) { + Slog.d(TAG, "Waking up all power groups"); + } + for (int idx = 0; idx < mPowerGroups.size(); idx++) { + wakePowerGroupLocked(mPowerGroups.valueAt(idx), mClock.uptimeMillis(), + PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag, opUid, + opPackageName, opUid); + } + return; + } + if (mPowerGroups.contains(powerGroupId)) { + if (DEBUG_SPEW) { + Slog.d(TAG, "Waking up power group " + powerGroupId); + } + wakePowerGroupLocked(mPowerGroups.get(powerGroupId), mClock.uptimeMillis(), + PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag, opUid, + opPackageName, opUid); + } } } } @@ -1972,7 +2029,7 @@ public final class PowerManagerService extends SystemService private boolean dozePowerGroupLocked(final PowerGroup powerGroup, long eventTime, int reason, int uid) { if (DEBUG_SPEW) { - Slog.d(TAG, "sleepDisplayGroupNoUpdateLocked: eventTime=" + eventTime + Slog.d(TAG, "dozePowerGroup: eventTime=" + eventTime + ", groupId=" + powerGroup.getGroupId() + ", reason=" + reason + ", uid=" + uid); } @@ -2661,8 +2718,8 @@ public final class PowerManagerService extends SystemService @GuardedBy("mLock") private void updateUserActivitySummaryLocked(long now, int dirty) { // Update the status of the user activity timeout timer. - if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS - | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) == 0) { + if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY + | DIRTY_WAKEFULNESS | DIRTY_SETTINGS | DIRTY_ATTENTIVE)) == 0) { return; } mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT); @@ -2746,6 +2803,11 @@ public final class PowerManagerService extends SystemService screenDimDuration); } + if (isAttentiveTimeoutExpired(powerGroup, now)) { + groupUserActivitySummary = 0; + groupNextTimeout = -1; + } + hasUserActivitySummary |= groupUserActivitySummary != 0; if (nextTimeout == -1) { @@ -3101,7 +3163,7 @@ public final class PowerManagerService extends SystemService Message msg = mHandler.obtainMessage(MSG_SANDMAN); msg.arg1 = powerGroup.getGroupId(); msg.setAsynchronous(true); - mHandler.sendMessage(msg); + mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); } } } diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index a486364518b9..8f4ddea1c30c 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -16,6 +16,7 @@ package com.android.server.trust; +import static android.service.trust.GrantTrustResult.STATUS_UNLOCKED_BY_GRANT; import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE; import android.Manifest; @@ -642,9 +643,7 @@ public class TrustManagerService extends SystemService { if (shouldSendCallback) { if (resultCallback != null) { if (DEBUG) Slog.d(TAG, "calling back with UNLOCKED_BY_GRANT"); - resultCallback.complete( - GrantTrustResult.withStatus( - GrantTrustResult.STATUS_UNLOCKED_BY_GRANT)); + resultCallback.complete(new GrantTrustResult(STATUS_UNLOCKED_BY_GRANT)); } } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 94f86462045a..0b52fd643a1c 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -856,6 +856,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean mEnteringAnimation; boolean mOverrideTaskTransition; + boolean mDismissKeyguardIfInsecure; boolean mAppStopped; // A hint to override the window specified rotation animation, or -1 to use the window specified @@ -1953,6 +1954,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } mOverrideTaskTransition = options.getOverrideTaskTransition(); + mDismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure(); } ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService( diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index c9b850181669..72408b67de41 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -544,10 +544,8 @@ public class ActivityStartController { if (mLastHomeActivityStartRecord != null && (!dumpPackagePresent || dumpPackage.equals(mLastHomeActivityStartRecord.packageName))) { - if (!dumped) { - dumped = true; - dumpLastHomeActivityStartResult(pw, prefix); - } + dumped = true; + dumpLastHomeActivityStartResult(pw, prefix); pw.print(prefix); pw.println("mLastHomeActivityStartRecord:"); mLastHomeActivityStartRecord.dump(pw, prefix + " ", true /* dumpAll */); @@ -565,6 +563,7 @@ public class ActivityStartController { dumpLastHomeActivityStartResult(pw, prefix); } pw.print(prefix); + pw.println("mLastStarter:"); mLastStarter.dump(pw, prefix + " "); if (dumpPackagePresent) { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 7b60ea7b9558..714aa5f404fb 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -614,6 +614,9 @@ class ActivityStarter { mVoiceInteractor = starter.mVoiceInteractor; mIntentDelivered = starter.mIntentDelivered; + mLastStartActivityResult = starter.mLastStartActivityResult; + mLastStartActivityTimeMs = starter.mLastStartActivityTimeMs; + mLastStartReason = starter.mLastStartReason; mRequest.set(starter.mRequest); } @@ -1599,7 +1602,6 @@ class ActivityStarter { TaskFragment inTaskFragment, boolean restrictedBgActivity, NeededUriGrants intentGrants) { int result = START_CANCELED; - boolean startResultSuccessful = false; final Task startedActivityRootTask; // Create a transition now to record the original intent of actions taken within @@ -1615,75 +1617,18 @@ class ActivityStarter { newTransition.setRemoteTransition(remoteTransition); } transitionController.collect(r); - final boolean isTransient = r.getOptions() != null && r.getOptions().getTransientLaunch(); try { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, inTaskFragment, restrictedBgActivity, intentGrants); - startResultSuccessful = ActivityManager.isStartResultSuccessful(result); - final boolean taskAlwaysOnTop = options != null && options.getTaskAlwaysOnTop(); - // Apply setAlwaysOnTop when starting an Activity is successful regardless of creating - // a new Activity or recycling the existing Activity. - if (taskAlwaysOnTop && startResultSuccessful) { - final Task targetRootTask = - mTargetRootTask != null ? mTargetRootTask : mTargetTask.getRootTask(); - targetRootTask.setAlwaysOnTop(true); - } } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); - startedActivityRootTask = handleStartResult(r, result); + startedActivityRootTask = handleStartResult(r, options, result, newTransition, + remoteTransition); mService.continueWindowLayout(); - mSupervisor.mUserLeaving = false; - - // Transition housekeeping - if (!startResultSuccessful) { - if (newTransition != null) { - newTransition.abort(); - } - } else { - if (!mAvoidMoveToFront && mDoResume - && mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade( - r.launchedFromUid)) { - // If the UID launching the activity has a visible window on top of the - // notification shade and it's launching an activity that's going to be at the - // front, we should move the shade out of the way so the user can see it. - // We want to avoid the case where the activity is launched on top of a - // background task which is not moved to the front. - StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal(); - if (statusBar != null) { - // This results in a async call since the interface is one-way - statusBar.collapsePanels(); - } - } - final boolean started = result == START_SUCCESS || result == START_TASK_TO_FRONT; - if (started) { - // The activity is started new rather than just brought forward, so record - // it as an existence change. - transitionController.collectExistenceChange(r); - } else if (result == START_DELIVERED_TO_TOP && newTransition != null) { - // We just delivered to top, so there isn't an actual transition here - newTransition.abort(); - newTransition = null; - } - if (isTransient) { - // `r` isn't guaranteed to be the actual relevant activity, so we must wait - // until after we launched to identify the relevant activity. - transitionController.setTransientLaunch(mLastStartActivityRecord, - mPriorAboveTask); - } - if (newTransition != null) { - transitionController.requestStartTransition(newTransition, - mTargetTask == null ? r.getTask() : mTargetTask, - remoteTransition, null /* displayChange */); - } else if (started) { - // Make the collecting transition wait until this request is ready. - transitionController.setReady(r, false); - } - } } - postStartActivityProcessing(r, result, startedActivityRootTask); return result; @@ -1695,40 +1640,89 @@ class ActivityStarter { * * @return the root task where the successful started activity resides. */ - private @Nullable Task handleStartResult(@NonNull ActivityRecord started, int result) { + private @Nullable Task handleStartResult(@NonNull ActivityRecord started, + ActivityOptions options, int result, Transition newTransition, + RemoteTransition remoteTransition) { + mSupervisor.mUserLeaving = false; final Task currentRootTask = started.getRootTask(); - Task startedActivityRootTask = currentRootTask != null ? currentRootTask : mTargetRootTask; + final Task startedActivityRootTask = + currentRootTask != null ? currentRootTask : mTargetRootTask; - if (ActivityManager.isStartResultSuccessful(result)) { - if (startedActivityRootTask != null) { - // If there is no state change (e.g. a resumed activity is reparented to top of - // another display) to trigger a visibility/configuration checking, we have to - // update the configuration for changing to different display. - final ActivityRecord currentTop = startedActivityRootTask.topRunningActivity(); - if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) { - mRootWindowContainer.ensureVisibilityAndConfig( - currentTop, currentTop.getDisplayId(), - true /* markFrozenIfConfigChanged */, false /* deferResume */); - } + if (!ActivityManager.isStartResultSuccessful(result) || startedActivityRootTask == null) { + // If we are not able to proceed, disassociate the activity from the task. Leaving an + // activity in an incomplete state can lead to issues, such as performing operations + // without a window container. + if (mStartActivity.getTask() != null) { + mStartActivity.finishIfPossible("startActivity", true /* oomAdj */); + } else if (mStartActivity.getParent() != null) { + mStartActivity.getParent().removeChild(mStartActivity); } - return startedActivityRootTask; - } - // If we are not able to proceed, disassociate the activity from the task. Leaving an - // activity in an incomplete state can lead to issues, such as performing operations - // without a window container. - if (mStartActivity.getTask() != null) { - mStartActivity.finishIfPossible("startActivity", true /* oomAdj */); - } else if (mStartActivity.getParent() != null) { - mStartActivity.getParent().removeChild(mStartActivity); + // Root task should also be detached from display and be removed if it's empty. + if (startedActivityRootTask != null && startedActivityRootTask.isAttached() + && !startedActivityRootTask.hasActivity() + && !startedActivityRootTask.isActivityTypeHome()) { + startedActivityRootTask.removeIfPossible("handleStartResult"); + } + if (newTransition != null) { + newTransition.abort(); + } + return null; } - // Root task should also be detached from display and be removed if it's empty. - if (startedActivityRootTask != null && startedActivityRootTask.isAttached() - && !startedActivityRootTask.hasActivity() - && !startedActivityRootTask.isActivityTypeHome()) { - startedActivityRootTask.removeIfPossible("handleStartResult"); - startedActivityRootTask = null; + // Apply setAlwaysOnTop when starting an activity is successful regardless of creating + // a new Activity or reusing the existing activity. + if (options != null && options.getTaskAlwaysOnTop()) { + startedActivityRootTask.setAlwaysOnTop(true); + } + + // If there is no state change (e.g. a resumed activity is reparented to top of + // another display) to trigger a visibility/configuration checking, we have to + // update the configuration for changing to different display. + final ActivityRecord currentTop = startedActivityRootTask.topRunningActivity(); + if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) { + mRootWindowContainer.ensureVisibilityAndConfig( + currentTop, currentTop.getDisplayId(), + true /* markFrozenIfConfigChanged */, false /* deferResume */); + } + + if (!mAvoidMoveToFront && mDoResume && mRootWindowContainer + .hasVisibleWindowAboveButDoesNotOwnNotificationShade(started.launchedFromUid)) { + // If the UID launching the activity has a visible window on top of the notification + // shade and it's launching an activity that's going to be at the front, we should move + // the shade out of the way so the user can see it. We want to avoid the case where the + // activity is launched on top of a background task which is not moved to the front. + final StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal(); + if (statusBar != null) { + // This results in a async call since the interface is one-way. + statusBar.collapsePanels(); + } + } + + // Transition housekeeping. + final TransitionController transitionController = started.mTransitionController; + final boolean isStarted = result == START_SUCCESS || result == START_TASK_TO_FRONT; + if (isStarted) { + // The activity is started new rather than just brought forward, so record it as an + // existence change. + transitionController.collectExistenceChange(started); + } else if (result == START_DELIVERED_TO_TOP && newTransition != null) { + // We just delivered to top, so there isn't an actual transition here. + newTransition.abort(); + newTransition = null; + } + if (options != null && options.getTransientLaunch()) { + // `started` isn't guaranteed to be the actual relevant activity, so we must wait + // until after we launched to identify the relevant activity. + transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask); + } + if (newTransition != null) { + transitionController.requestStartTransition(newTransition, + mTargetTask == null ? started.getTask() : mTargetTask, + remoteTransition, null /* displayChange */); + } else if (isStarted) { + // Make the collecting transition wait until this request is ready. + transitionController.setReady(started, false); } return startedActivityRootTask; } @@ -2951,7 +2945,8 @@ class ActivityStarter { final boolean onTop = (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind; - return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, mSourceRootTask, onTop, + final Task sourceTask = mSourceRecord != null ? mSourceRecord.getTask() : null; + return mRootWindowContainer.getOrCreateRootTask(r, aOptions, task, sourceTask, onTop, mLaunchParams, launchFlags); } @@ -3169,7 +3164,6 @@ class ActivityStarter { } void dump(PrintWriter pw, String prefix) { - prefix = prefix + " "; pw.print(prefix); pw.print("mCurrentUser="); pw.println(mRootWindowContainer.mCurrentUser); @@ -3215,7 +3209,7 @@ class ActivityStarter { pw.print(" mDoResume="); pw.print(mDoResume); pw.print(" mAddingToTask="); - pw.println(mAddingToTask); + pw.print(mAddingToTask); pw.print(" mInTaskFragment="); pw.println(mInTaskFragment); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index ad6f35452051..eacf205c088c 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -421,30 +421,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { // How long to wait in getAutofillAssistStructure() for the activity to respond with the result. private static final int PENDING_AUTOFILL_ASSIST_STRUCTURE_TIMEOUT = 2000; - // Permission tokens are used to temporarily granted a trusted app the ability to call - // #startActivityAsCaller. A client is expected to dump its token after this time has elapsed, - // showing any appropriate error messages to the user. - private static final long START_AS_CALLER_TOKEN_TIMEOUT = - 10 * MINUTE_IN_MILLIS; - - // How long before the service actually expires a token. This is slightly longer than - // START_AS_CALLER_TOKEN_TIMEOUT, to provide a buffer so clients will rarely encounter the - // expiration exception. - private static final long START_AS_CALLER_TOKEN_TIMEOUT_IMPL = - START_AS_CALLER_TOKEN_TIMEOUT + 2 * 1000; - - // How long the service will remember expired tokens, for the purpose of providing error - // messaging when a client uses an expired token. - private static final long START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT = - START_AS_CALLER_TOKEN_TIMEOUT_IMPL + 20 * MINUTE_IN_MILLIS; - - // The component name of the delegated activities that are allowed to call - // #startActivityAsCaller with the one-time used permission token. - final HashMap<IBinder, ComponentName> mStartActivitySources = new HashMap<>(); - - // Permission tokens that have expired, but we remember for error reporting. - final ArrayList<IBinder> mExpiredStartAsCallerTokens = new ArrayList<>(); - private final ArrayList<PendingAssistExtras> mPendingAssistExtras = new ArrayList<>(); // Keeps track of the active voice interaction service component, notified from @@ -1547,41 +1523,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public IBinder requestStartActivityPermissionToken(ComponentName componentName) { - int callingUid = Binder.getCallingUid(); - if (UserHandle.getAppId(callingUid) != SYSTEM_UID) { - throw new SecurityException("Only the system process can request a permission token, " - + "received request from uid: " + callingUid); - } - IBinder permissionToken = new Binder(); - synchronized (mGlobalLock) { - mStartActivitySources.put(permissionToken, componentName); - } - - Message expireMsg = PooledLambda.obtainMessage( - ActivityTaskManagerService::expireStartAsCallerTokenMsg, this, permissionToken); - mUiHandler.sendMessageDelayed(expireMsg, START_AS_CALLER_TOKEN_TIMEOUT_IMPL); - - Message forgetMsg = PooledLambda.obtainMessage( - ActivityTaskManagerService::forgetStartAsCallerTokenMsg, this, permissionToken); - mUiHandler.sendMessageDelayed(forgetMsg, START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT); - - return permissionToken; - } - - @Override public final int startActivityAsCaller(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, - int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, IBinder permissionToken, + int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, boolean ignoreTargetSecurity, int userId) { // This is very dangerous -- it allows you to perform a start activity (including // permission grants) as any app that may launch one of your own activities. So we only // allow this in two cases: - // 1) The caller is an activity that is part of the core framework, and then only when it - // is running as the system. - // 2) The caller provides a valid permissionToken. Permission tokens are one-time use and - // can only be requested from system uid, which may then delegate this call to - // another app. + // 1) The calling process holds the signature permission START_ACTIVITY_AS_CALLER + // + // 2) The calling process is an activity belonging to the package "android" which is + // running as UID_SYSTEM or as the target UID (the activity which started the activity + // calling this method). + final ActivityRecord sourceRecord; final int targetUid; final String targetPackage; @@ -1600,26 +1554,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { throw new SecurityException("Called without a process attached to activity"); } - final ComponentName componentName; - if (permissionToken != null) { - // To even attempt to use a permissionToken, an app must also have this signature - // permission. - mAmInternal.enforceCallingPermission( - android.Manifest.permission.START_ACTIVITY_AS_CALLER, - "startActivityAsCaller"); - // If called with a permissionToken, the caller must be the same component that - // was allowed to use the permissionToken. - componentName = mStartActivitySources.remove(permissionToken); - if (!sourceRecord.mActivityComponent.equals(componentName)) { - if (mExpiredStartAsCallerTokens.contains(permissionToken)) { - throw new SecurityException("Called with expired permission token: " - + permissionToken); - } else { - throw new SecurityException("Called with invalid permission token: " - + permissionToken); - } - } - } else { + if (checkCallingPermission(Manifest.permission.START_ACTIVITY_AS_CALLER) + != PERMISSION_GRANTED) { // Whether called directly or from a delegate, the source activity must be from the // android package. if (!sourceRecord.info.packageName.equals("android")) { @@ -4453,15 +4389,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Settings.System.putConfigurationForUser(resolver, config, userId); } - private void expireStartAsCallerTokenMsg(IBinder permissionToken) { - mStartActivitySources.remove(permissionToken); - mExpiredStartAsCallerTokens.add(permissionToken); - } - - private void forgetStartAsCallerTokenMsg(IBinder permissionToken) { - mExpiredStartAsCallerTokens.remove(permissionToken); - } - boolean isActivityStartsLoggingEnabled() { return mAmInternal.isActivityStartsLoggingEnabled(); } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index a31d8603e2f2..0b4d8876cf8f 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -666,22 +666,19 @@ public class AppTransitionController { "Override with TaskFragment remote animation for transit=%s", AppTransition.appTransitionOldToString(transit)); - final boolean hasUntrustedEmbedding = task.forAllLeafTasks( - taskFragment -> !taskFragment.isAllowedToBeEmbeddedInTrustedMode()); final RemoteAnimationController remoteAnimationController = mDisplayContent.mAppTransition.getRemoteAnimationController(); - if (hasUntrustedEmbedding && remoteAnimationController != null) { - // We are going to use client-driven animation, but the Task is in untrusted embedded - // mode. We need to disable all input on activity windows during the animation to - // ensure it is safe. This is needed for all activity windows in the animation Task. + if (remoteAnimationController != null) { + // We are going to use client-driven animation, Disable all input on activity windows + // during the animation to ensure it is safe to allow client to animate the surfaces. + // This is needed for all activity windows in the animation Task. remoteAnimationController.setOnRemoteAnimationReady(() -> { final Consumer<ActivityRecord> updateActivities = activity -> activity.setDropInputForAnimation(true); task.forAllActivities(updateActivities); }); - ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "Task=%d contains embedded TaskFragment in" - + " untrusted mode. Disabled all input during TaskFragment remote animation.", - task.mTaskId); + ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "Task=%d contains embedded TaskFragment." + + " Disabled all input during TaskFragment remote animation.", task.mTaskId); } return true; } diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index 5c1ddd964325..6e205be5b574 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -30,6 +30,8 @@ import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; +import java.util.ArrayList; + /** * Utility class for collecting WindowContainers that will merge transactions. * For example to use to synchronously resize all the children of a window container @@ -64,9 +66,17 @@ class BLASTSyncEngine { void onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction); } - interface SyncEngineListener { - /** Called when there is no more active sync set. */ - void onSyncEngineFree(); + /** + * Represents the desire to make a {@link BLASTSyncEngine.SyncGroup} while another is active. + * + * @see #queueSyncSet + */ + private static class PendingSyncSet { + /** Called immediately when the {@link BLASTSyncEngine} is free. */ + private Runnable mStartSync; + + /** Posted to the main handler after {@link #mStartSync} is called. */ + private Runnable mApplySync; } /** @@ -142,8 +152,21 @@ class BLASTSyncEngine { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); mActiveSyncs.remove(mSyncId); mWm.mH.removeCallbacks(mOnTimeout); - if (mSyncEngineListener != null && mActiveSyncs.size() == 0) { - mSyncEngineListener.onSyncEngineFree(); + + // Immediately start the next pending sync-transaction if there is one. + if (mActiveSyncs.size() == 0 && !mPendingSyncSets.isEmpty()) { + ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "PendingStartTransaction found"); + final PendingSyncSet pt = mPendingSyncSets.remove(0); + pt.mStartSync.run(); + if (mActiveSyncs.size() == 0) { + throw new IllegalStateException("Pending Sync Set didn't start a sync."); + } + // Post this so that the now-playing transition setup isn't interrupted. + mWm.mH.post(() -> { + synchronized (mWm.mGlobalLock) { + pt.mApplySync.run(); + } + }); } } @@ -183,17 +206,18 @@ class BLASTSyncEngine { private final WindowManagerService mWm; private int mNextSyncId = 0; private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>(); - private SyncEngineListener mSyncEngineListener; + + /** + * A queue of pending sync-sets waiting for their turn to run. + * + * @see #queueSyncSet + */ + private final ArrayList<PendingSyncSet> mPendingSyncSets = new ArrayList<>(); BLASTSyncEngine(WindowManagerService wms) { mWm = wms; } - /** Sets listener listening to whether the sync engine is free. */ - void setSyncEngineListener(SyncEngineListener listener) { - mSyncEngineListener = listener; - } - /** * Prepares a {@link SyncGroup} that is not active yet. Caller must call {@link #startSyncSet} * before calling {@link #addToSyncSet(int, WindowContainer)} on any {@link WindowContainer}. @@ -275,4 +299,31 @@ class BLASTSyncEngine { mActiveSyncs.valueAt(i).onSurfacePlacement(); } } + + /** + * Queues a sync operation onto this engine. It will wait until any current/prior sync-sets + * have finished to run. This is needed right now because currently {@link BLASTSyncEngine} + * only supports 1 sync at a time. + * + * Code-paths should avoid using this unless absolutely necessary. Usually, we use this for + * difficult edge-cases that we hope to clean-up later. + * + * @param startSync will be called immediately when the {@link BLASTSyncEngine} is free to + * "reserve" the {@link BLASTSyncEngine} by calling one of the + * {@link BLASTSyncEngine#startSyncSet} variants. + * @param applySync will be posted to the main handler after {@code startSync} has been + * called. This is posted so that it doesn't interrupt any clean-up for the + * prior sync-set. + */ + void queueSyncSet(@NonNull Runnable startSync, @NonNull Runnable applySync) { + final PendingSyncSet pt = new PendingSyncSet(); + pt.mStartSync = startSync; + pt.mApplySync = applySync; + mPendingSyncSets.add(pt); + } + + /** @return {@code true} if there are any sync-sets waiting to start. */ + boolean hasPendingSyncSets() { + return !mPendingSyncSets.isEmpty(); + } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 61cd22170e18..8eb0046ff923 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -4071,12 +4071,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp t.setColorSpace(activity.mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB)); t.setLayer(imeSurface, 1); - final Point surfacePosition = new Point( - imeWindow.getFrame().left - mImeTarget.getFrame().left, - imeWindow.getFrame().top - mImeTarget.getFrame().top); + final Point surfacePosition = new Point(imeWindow.getFrame().left, + imeWindow.getFrame().top); if (imeParent == activity.getSurfaceControl()) { t.setPosition(imeSurface, surfacePosition.x, surfacePosition.y); } else { + surfacePosition.offset(-mImeTarget.getFrame().left, -mImeTarget.getFrame().top); surfacePosition.offset(mImeTarget.mAttrs.surfaceInsets.left, mImeTarget.mAttrs.surfaceInsets.top); t.setPosition(imeSurface, surfacePosition.x, surfacePosition.y); diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 7bf150b18e9b..2ebb59751634 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -28,6 +28,7 @@ import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_W import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; +import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS; @@ -408,6 +409,25 @@ class KeyguardController { } /** + * Called when keyguard going away state changed. + */ + private void handleKeyguardGoingAwayChanged(DisplayContent dc) { + mService.deferWindowLayout(); + try { + dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, 0 /* transitFlags */); + // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use + // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going + // away. + dc.mAtmService.getTransitionController().requestTransitionIfNeeded( + TRANSIT_OPEN, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, null /* trigger */, dc); + updateKeyguardSleepToken(); + mWindowManager.executeAppTransition(); + } finally { + mService.continueWindowLayout(); + } + } + + /** * Called when somebody wants to dismiss the Keyguard via the flag. */ private void handleDismissKeyguard(int displayId) { @@ -533,11 +553,13 @@ class KeyguardController { } /** - * Updates {@link #mOccluded}, {@link #mTopTurnScreenOnActivity} and - * {@link #mDismissingKeyguardActivity} if the top task could be visible. + * Updates keyguard status if the top task could be visible. The top task may occlude + * keyguard, request to dismiss keyguard or make insecure keyguard go away based on its + * properties. */ void updateVisibility(KeyguardController controller, DisplayContent display) { final boolean lastOccluded = mOccluded; + final boolean lastKeyguardGoingAway = mKeyguardGoingAway; final ActivityRecord lastDismissKeyguardActivity = mDismissingKeyguardActivity; final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity; @@ -561,14 +583,18 @@ class KeyguardController { mTopTurnScreenOnActivity = top; } - final boolean showWhenLocked = top.canShowWhenLocked(); - if (showWhenLocked) { + final boolean isKeyguardSecure = controller.mWindowManager.isKeyguardSecure( + controller.mService.getCurrentUserId()); + if (top.mDismissKeyguardIfInsecure && mKeyguardShowing && !isKeyguardSecure) { + mKeyguardGoingAway = true; + } else if (top.canShowWhenLocked()) { mTopOccludesActivity = top; } // Only the top activity may control occluded, as we can't occlude the Keyguard // if the top app doesn't want to occlude it. - occludedByActivity = showWhenLocked || (mDismissingKeyguardActivity != null + occludedByActivity = mTopOccludesActivity != null + || (mDismissingKeyguardActivity != null && task.topRunningActivity() == mDismissingKeyguardActivity && controller.canShowWhileOccluded( true /* dismissKeyguard */, false /* showWhenLocked */)); @@ -583,10 +609,8 @@ class KeyguardController { && top.getActivityType() == ACTIVITY_TYPE_DREAM); mOccluded = mShowingDream || occludedByActivity; mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity - && !mOccluded - && mDismissingKeyguardActivity != null - && controller.mWindowManager.isKeyguardSecure( - controller.mService.getCurrentUserId()); + && !mOccluded && !mKeyguardGoingAway + && mDismissingKeyguardActivity != null; if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity && mTopTurnScreenOnActivity != null @@ -598,6 +622,8 @@ class KeyguardController { if (lastOccluded != mOccluded) { controller.handleOccludedChanged(mDisplayId, mTopOccludesActivity); + } else if (!lastKeyguardGoingAway && mKeyguardGoingAway) { + controller.handleKeyguardGoingAwayChanged(display); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f3cefca10b06..731a04500b57 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2360,6 +2360,20 @@ class Task extends TaskFragment { return parentTask == null ? null : parentTask.getOrganizedTask(); } + /** @return the first create-by-organizer task. */ + @Nullable + Task getCreatedByOrganizerTask() { + if (mCreatedByOrganizer) { + return this; + } + final WindowContainer parent = getParent(); + if (parent == null) { + return null; + } + final Task parentTask = parent.asTask(); + return parentTask == null ? null : parentTask.getCreatedByOrganizerTask(); + } + // TODO(task-merge): Figure out what's the right thing to do for places that used it. boolean isRootTask() { return getRootTask() == this; diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java index 3b7927470e64..61963c48a14c 100644 --- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java @@ -20,6 +20,7 @@ import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ITaskStackListener; import android.app.TaskInfo; +import android.app.TaskStackListener; import android.content.ComponentName; import android.os.Binder; import android.os.Handler; @@ -286,6 +287,9 @@ class TaskChangeNotificationController { if (listener instanceof Binder) { synchronized (mLocalTaskStackListeners) { if (!mLocalTaskStackListeners.contains(listener)) { + if (listener instanceof TaskStackListener) { + ((TaskStackListener) listener).setIsLocal(); + } mLocalTaskStackListeners.add(listener); } } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 7bb7870cea80..7a7bf1f877b9 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1125,9 +1125,9 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0 && mLaunchAdjacentFlagRootTask != null) { // If the adjacent launch is coming from the same root, launch to adjacent root instead. - if (sourceTask != null - && sourceTask.getRootTask().mTaskId == mLaunchAdjacentFlagRootTask.mTaskId - && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null) { + if (sourceTask != null && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null + && (sourceTask == mLaunchAdjacentFlagRootTask + || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) { return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask(); } else { return mLaunchAdjacentFlagRootTask; @@ -1141,18 +1141,22 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { ? launchRootTask.getAdjacentTaskFragment() : null; final Task adjacentRootTask = adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null; - if (sourceTask != null && sourceTask.getRootTask() == adjacentRootTask) { + if (sourceTask != null && adjacentRootTask != null + && (sourceTask == adjacentRootTask + || sourceTask.isDescendantOf(adjacentRootTask))) { return adjacentRootTask; } else { return launchRootTask; } } } - // For better split UX, If task launch by the source task which root task is created by - // organizer, it should also launch in that root too. - if (sourceTask != null && sourceTask.getRootTask().mCreatedByOrganizer) { - return sourceTask.getRootTask(); + + // For a better split UX, If a task is launching from a created-by-organizer task, it should + // be launched into the same created-by-organizer task as well. + if (sourceTask != null) { + return sourceTask.getCreatedByOrganizerTask(); } + return null; } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index b8b151f0e9d4..3a8c8c7d6c94 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -31,6 +31,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration; import android.content.Intent; import android.content.pm.ParceledListSlice; +import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; @@ -474,10 +475,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } } - static SurfaceControl applyStartingWindowAnimation(WindowContainer window) { + static SurfaceControl applyStartingWindowAnimation(WindowState window) { + final SurfaceControl.Transaction t = window.getPendingTransaction(); + final Rect mainFrame = window.getRelativeFrame(); final StartingWindowAnimationAdaptor adaptor = new StartingWindowAnimationAdaptor(); - window.startAnimation(window.getPendingTransaction(), adaptor, false, - ANIMATION_TYPE_STARTING_REVEAL); + window.startAnimation(t, adaptor, false, ANIMATION_TYPE_STARTING_REVEAL); + t.setPosition(adaptor.mAnimationLeash, mainFrame.left, mainFrame.top); return adaptor.mAnimationLeash; } @@ -530,8 +533,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final SurfaceControl.Transaction t = mainWindow.getPendingTransaction(); removalInfo.windowAnimationLeash = applyStartingWindowAnimation(mainWindow); removalInfo.mainFrame = mainWindow.getRelativeFrame(); - t.setPosition(removalInfo.windowAnimationLeash, - removalInfo.mainFrame.left, removalInfo.mainFrame.top); } } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index cde99271b0ae..814656db9fa0 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -480,12 +480,17 @@ class TaskSnapshotController { } final HardwareBuffer buffer = screenshotBuffer == null ? null : screenshotBuffer.getHardwareBuffer(); - if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { + if (isInvalidHardwareBuffer(buffer)) { return null; } return screenshotBuffer; } + static boolean isInvalidHardwareBuffer(HardwareBuffer buffer) { + return buffer == null || buffer.isClosed() // This must be checked before getting size. + || buffer.getWidth() <= 1 || buffer.getHeight() <= 1; + } + @Nullable TaskSnapshot snapshotTask(Task task) { return snapshotTask(task, PixelFormat.UNKNOWN); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index 9fbcd7cc5d84..03098e3eaca9 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -407,6 +407,10 @@ class TaskSnapshotPersister { } boolean writeBuffer() { + if (TaskSnapshotController.isInvalidHardwareBuffer(mSnapshot.getHardwareBuffer())) { + Slog.e(TAG, "Invalid task snapshot hw buffer, taskId=" + mTaskId); + return false; + } final Bitmap bitmap = Bitmap.wrapHardwareBuffer( mSnapshot.getHardwareBuffer(), mSnapshot.getColorSpace()); if (bitmap == null) { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index a0d68a1adb8a..973f98310d3e 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -189,6 +189,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe private boolean mNavBarAttachedToApp = false; private int mRecentsDisplayId = INVALID_DISPLAY; + /** @see #setCanPipOnFinish */ + private boolean mCanPipOnFinish = true; + Transition(@TransitionType int type, @TransitionFlags int flags, TransitionController controller, BLASTSyncEngine syncEngine) { mType = type; @@ -448,6 +451,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } /** + * Set whether this transition can start a pip-enter transition when finished. This is usually + * true, but gets set to false when recents decides that it wants to finish its animation but + * not actually finish its animation (yeah...). + */ + void setCanPipOnFinish(boolean canPipOnFinish) { + mCanPipOnFinish = canPipOnFinish; + } + + /** * The transition has finished animating and is ready to finalize WM state. This should not * be called directly; use {@link TransitionController#finishTransition} instead. */ @@ -475,7 +487,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe // activity in a bad state. if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) { boolean commitVisibility = true; - if (ar.isVisible() && ar.getTask() != null) { + if (mCanPipOnFinish && ar.isVisible() && ar.getTask() != null) { if (ar.pictureInPictureArgs != null && ar.pictureInPictureArgs.isAutoEnterEnabled()) { if (mTransientLaunches != null) { diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 18851b34ec04..23479a269de7 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -99,9 +99,6 @@ class TransitionController { // TODO(b/188595497): remove when not needed. final StatusBarManagerInternal mStatusBar; - /** Pending transitions from Shell that are waiting the SyncEngine to be free. */ - private final ArrayList<PendingStartTransition> mPendingTransitions = new ArrayList<>(); - TransitionController(ActivityTaskManagerService atm, TaskSnapshotController taskSnapshotController) { mAtm = atm; @@ -146,7 +143,7 @@ class TransitionController { } /** Starts Collecting */ - private void moveToCollecting(@NonNull Transition transition) { + void moveToCollecting(@NonNull Transition transition) { if (mCollectingTransition != null) { throw new IllegalStateException("Simultaneous transition collection not supported."); } @@ -160,26 +157,6 @@ class TransitionController { dispatchLegacyAppTransitionPending(); } - /** Creates a transition representation but doesn't start collecting. */ - @NonNull - PendingStartTransition createPendingTransition(@WindowManager.TransitionType int type) { - if (mTransitionPlayer == null) { - throw new IllegalStateException("Shell Transitions not enabled"); - } - final PendingStartTransition out = new PendingStartTransition(new Transition(type, - 0 /* flags */, this, mAtm.mWindowManager.mSyncEngine)); - mPendingTransitions.add(out); - // We want to start collecting immediately when the engine is free, otherwise it may - // be busy again. - out.setStartSync(() -> { - mPendingTransitions.remove(out); - moveToCollecting(out.mTransition); - }); - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating PendingTransition: %s", - out.mTransition); - return out; - } - void registerTransitionPlayer(@Nullable ITransitionPlayer player, @Nullable IApplicationThread appThread) { try { @@ -601,24 +578,16 @@ class TransitionController { if (!mPlayingTransitions.isEmpty()) { state = LEGACY_STATE_RUNNING; } else if ((mCollectingTransition != null && mCollectingTransition.getLegacyIsReady()) - || !mPendingTransitions.isEmpty()) { - // The transition may not be "ready", but we have transition waiting to start, so it - // can't be IDLE for test purpose. Ideally, we should have a STATE_COLLECTING. + || mAtm.mWindowManager.mSyncEngine.hasPendingSyncSets()) { + // The transition may not be "ready", but we have a sync-transaction waiting to start. + // Usually the pending transaction is for a transition, so assuming that is the case, + // we can't be IDLE for test purposes. Ideally, we should have a STATE_COLLECTING. state = LEGACY_STATE_READY; } proto.write(AppTransitionProto.APP_TRANSITION_STATE, state); proto.end(token); } - /** Represents a startTransition call made while there is other active BLAST SyncGroup. */ - class PendingStartTransition extends WindowOrganizerController.PendingTransaction { - final Transition mTransition; - - PendingStartTransition(Transition transition) { - mTransition = transition; - } - } - static class TransitionMetricsReporter extends ITransitionMetricsReporter.Stub { private final ArrayMap<IBinder, LongConsumer> mMetricConsumers = new ArrayMap<>(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 41215014f859..92864b6e3fd7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -9045,13 +9045,18 @@ public class WindowManagerService extends IWindowManager.Stub } TaskSnapshot taskSnapshot; - synchronized (mGlobalLock) { - Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS); - if (task == null) { - throw new IllegalArgumentException( - "Failed to find matching task for taskId=" + taskId); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + Task task = mRoot.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS); + if (task == null) { + throw new IllegalArgumentException( + "Failed to find matching task for taskId=" + taskId); + } + taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false); } - taskSnapshot = mTaskSnapshotController.captureTaskSnapshot(task, false); + } finally { + Binder.restoreCallingIdentity(token); } if (taskSnapshot == null || taskSnapshot.getHardwareBuffer() == null) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index fe5f6759a17a..b5cf708eb46d 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -99,7 +99,7 @@ import java.util.function.IntSupplier; * @see android.window.WindowOrganizer */ class WindowOrganizerController extends IWindowOrganizerController.Stub - implements BLASTSyncEngine.TransactionReadyListener, BLASTSyncEngine.SyncEngineListener { + implements BLASTSyncEngine.TransactionReadyListener { private static final String TAG = "WindowOrganizerController"; @@ -122,21 +122,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub private final HashMap<Integer, IWindowContainerTransactionCallback> mTransactionCallbacksByPendingSyncId = new HashMap(); - /** - * A queue of transaction waiting for their turn to sync. Currently {@link BLASTSyncEngine} only - * supports 1 sync at a time, so we have to queue them. - * - * WMCore has enough information to ensure that it won't end up collecting multiple transitions - * in parallel by itself; however, Shell can start transitions/apply sync transaction at - * arbitrary times via {@link WindowOrganizerController#startTransition} and - * {@link WindowOrganizerController#applySyncTransaction}, so we have to support those coming in - * at any time (even while already syncing). - * - * This is really just a back-up for unrealistic situations (eg. during tests). In practice, - * this shouldn't ever happen. - */ - private final ArrayList<PendingTransaction> mPendingTransactions = new ArrayList<>(); - final TaskOrganizerController mTaskOrganizerController; final DisplayAreaOrganizerController mDisplayAreaOrganizerController; final TaskFragmentOrganizerController mTaskFragmentOrganizerController; @@ -160,7 +145,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub void setWindowManager(WindowManagerService wms) { mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController); mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier); - wms.mSyncEngine.setSyncEngineListener(this); } TransitionController getTransitionController() { @@ -231,16 +215,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } else { // Because the BLAST engine only supports one sync at a time, queue the // transaction. - final PendingTransaction pt = new PendingTransaction(); - // Start sync group immediately when the SyncEngine is free. - pt.setStartSync(() -> - mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup)); - // Those will be post so that it won't interrupt ongoing transition. - pt.setStartTransaction(() -> { - applyTransaction(t, syncId, null /*transition*/, caller); - setSyncReady(syncId); - }); - mPendingTransactions.add(pt); + mService.mWindowManager.mSyncEngine.queueSyncSet( + () -> mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup), + () -> { + applyTransaction(t, syncId, null /*transition*/, caller); + setSyncReady(syncId); + }); } return syncId; } @@ -283,19 +263,24 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // transition starts collecting. This should almost never happen except during // tests. if (mService.mWindowManager.mSyncEngine.hasActiveSync()) { - Slog.e(TAG, "startTransition() while one is already collecting."); - final TransitionController.PendingStartTransition pt = - mTransitionController.createPendingTransition(type); - // Those will be post so that it won't interrupt ongoing transition. - pt.setStartTransaction(() -> { - pt.mTransition.start(); - applyTransaction(wct, -1 /*syncId*/, pt.mTransition, caller); - if (needsSetReady) { - pt.mTransition.setAllReady(); - } - }); - mPendingTransactions.add(pt); - return pt.mTransition; + Slog.w(TAG, "startTransition() while one is already collecting."); + final Transition nextTransition = new Transition(type, 0 /* flags */, + mTransitionController, mService.mWindowManager.mSyncEngine); + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + "Creating Pending Transition: %s", nextTransition); + mService.mWindowManager.mSyncEngine.queueSyncSet( + // Make sure to collect immediately to prevent another transition + // from sneaking in before it. Note: moveToCollecting internally + // calls startSyncSet. + () -> mTransitionController.moveToCollecting(nextTransition), + () -> { + nextTransition.start(); + applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); + if (needsSetReady) { + nextTransition.setAllReady(); + } + }); + return nextTransition; } transition = mTransitionController.createTransition(type); } @@ -426,6 +411,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } if (transition != null) transition.collect(wc); + if (finishTransition != null) { + // Deal with edge-cases in recents where it pretends to finish itself. + if ((entry.getValue().getChangeMask() + & WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) { + finishTransition.setCanPipOnFinish(false /* canPipOnFinish */); + } + } + int containerEffect = applyWindowContainerChange(wc, entry.getValue()); effects |= containerEffect; @@ -1190,23 +1183,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } @Override - public void onSyncEngineFree() { - if (mPendingTransactions.isEmpty()) { - return; - } - - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "PendingStartTransaction found"); - final PendingTransaction pt = mPendingTransactions.remove(0); - pt.startSync(); - // Post this so that the now-playing transition setup isn't interrupted. - mService.mH.post(() -> { - synchronized (mGlobalLock) { - pt.startTransaction(); - } - }); - } - - @Override public void registerTransitionPlayer(ITransitionPlayer player) { enforceTaskPermission("registerTransitionPlayer()"); final int callerPid = Binder.getCallingPid(); @@ -1555,38 +1531,4 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub + result + " when starting " + intent); } } - - /** - * Represents a sync {@link WindowContainerTransaction} call made while there is other active - * {@link BLASTSyncEngine.SyncGroup}. - */ - static class PendingTransaction { - private Runnable mStartSync; - private Runnable mStartTransaction; - - /** - * The callback will be called immediately when the {@link BLASTSyncEngine} is free. One - * should call {@link BLASTSyncEngine#startSyncSet(BLASTSyncEngine.SyncGroup)} here to - * reserve the {@link BLASTSyncEngine}. - */ - void setStartSync(@NonNull Runnable callback) { - mStartSync = callback; - } - - /** - * The callback will be post to the main handler after the {@link BLASTSyncEngine} is free - * to apply the pending {@link WindowContainerTransaction}. - */ - void setStartTransaction(@NonNull Runnable callback) { - mStartTransaction = callback; - } - - private void startSync() { - mStartSync.run(); - } - - private void startTransaction() { - mStartTransaction.run(); - } - } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 0ca1058a80b2..b20781fd91ec 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3962,8 +3962,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP try { mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration, - forceRelayout, alwaysConsumeSystemBars, displayId, Integer.MAX_VALUE, - resizeMode); + forceRelayout, alwaysConsumeSystemBars, displayId, mSyncSeqId, resizeMode); + if (drawPending && reportOrientation && mOrientationChanging) { mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime(); ProtoLog.v(WM_DEBUG_ORIENTATION, @@ -5288,7 +5288,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mControllableInsetProvider != null) { return; } - if (mDisplayContent.inTransition()) { + if (getDisplayContent().inTransition()) { // Skip because the animation is usually unnoticeable (e.g. covered by rotation // animation) and the animation bounds could be inconsistent, such as depending // on when the window applies its draw transaction with new rotation. diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 55e504a3b611..b0fe3974770f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -7233,7 +7233,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; } Preconditions.checkCallAuthorization( - hasCallingOrSelfPermission(permission.SEND_LOST_MODE_LOCATION_UPDATES)); + hasCallingOrSelfPermission(permission.TRIGGER_LOST_MODE)); synchronized (getLockObject()) { final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked( @@ -13986,16 +13986,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; } } - try { - if (!isRuntimePermission(permission)) { - callback.sendResult(null); - return; - } - } catch (NameNotFoundException e) { - throw new RemoteException("Cannot check if " + permission - + "is a runtime permission", e, false, true); + if (!isRuntimePermission(permission)) { + callback.sendResult(null); + return; } - if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) { @@ -14108,11 +14102,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { }); } - public boolean isRuntimePermission(String permissionName) throws NameNotFoundException { - final PackageManager packageManager = mInjector.getPackageManager(); - PermissionInfo permissionInfo = packageManager.getPermissionInfo(permissionName, 0); - return (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) - == PermissionInfo.PROTECTION_DANGEROUS; + private boolean isRuntimePermission(String permissionName) { + try { + final PackageManager packageManager = mInjector.getPackageManager(); + PermissionInfo permissionInfo = packageManager.getPermissionInfo(permissionName, 0); + return (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) + == PermissionInfo.PROTECTION_DANGEROUS; + } catch (NameNotFoundException e) { + return false; + } } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java index 964be38943bf..c72e1eabb086 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java @@ -16,6 +16,8 @@ package com.android.server.devicepolicy; +import static com.android.server.FactoryResetter.setFactoryResetting; + import android.annotation.Nullable; import android.app.admin.DevicePolicySafetyChecker; import android.content.Context; @@ -36,7 +38,10 @@ import java.util.Objects; /** * Entry point for "factory reset" requests. + * + * @deprecated TODO(b/225012970): should be moved to {@code com.android.server.FactoryResetter} */ +@Deprecated public final class FactoryResetter { private static final String TAG = FactoryResetter.class.getSimpleName(); @@ -60,6 +65,8 @@ public final class FactoryResetter { Preconditions.checkCallAuthorization(mContext.checkCallingOrSelfPermission( android.Manifest.permission.MASTER_CLEAR) == PackageManager.PERMISSION_GRANTED); + setFactoryResetting(mContext); + if (mSafetyChecker == null) { factoryResetInternalUnchecked(); return true; diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index e09668756f10..4a51e41b1dc5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -217,6 +217,8 @@ public class AlarmManagerServiceTest { @Mock private AppOpsManager mAppOpsManager; @Mock + private BatteryManager mBatteryManager; + @Mock private DeviceIdleInternal mDeviceIdleInternal; @Mock private PermissionManagerServiceInternal mPermissionManagerInternal; @@ -453,6 +455,7 @@ public class AlarmManagerServiceTest { eq(Manifest.permission.USE_EXACT_ALARM), anyInt(), anyInt(), anyString())); when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager); + when(mMockContext.getSystemService(BatteryManager.class)).thenReturn(mBatteryManager); registerAppIds(new String[]{TEST_CALLING_PACKAGE}, new Integer[]{UserHandle.getAppId(TEST_CALLING_UID)}); @@ -477,6 +480,8 @@ public class AlarmManagerServiceTest { // Other boot phases don't matter mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); + + verify(mBatteryManager).isCharging(); setTareEnabled(false); mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW; mAllowWhileIdleWindow = mService.mConstants.ALLOW_WHILE_IDLE_WINDOW; @@ -1101,6 +1106,7 @@ public class AlarmManagerServiceTest { new Intent(parole ? BatteryManager.ACTION_CHARGING : BatteryManager.ACTION_DISCHARGING)); assertAndHandleMessageSync(CHARGING_STATUS_CHANGED); + assertEquals(parole, mService.mAppStandbyParole); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java index 457c8db9fdf3..4ffa0fbec758 100644 --- a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java @@ -14,11 +14,13 @@ * limitations under the License. */ +// TODO(b/225012970): should be moved to com.android.server package com.android.server.devicepolicy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.FactoryResetter.isFactoryResetting; import static com.google.common.truth.Truth.assertThat; @@ -165,6 +167,7 @@ public final class FactoryResetterTest { .factoryReset(); assertThat(success).isTrue(); + assertThat(isFactoryResetting()).isTrue(); verifyWipeAdoptableStorageCalled(); verifyWipeFactoryResetProtectionNotCalled(); verifyRebootWipeUserDataMinimumArgsCalled(); @@ -179,6 +182,7 @@ public final class FactoryResetterTest { .build().factoryReset(); assertThat(success).isTrue(); + assertThat(isFactoryResetting()).isTrue(); verifyWipeAdoptableStorageNotCalled(); verifyWipeFactoryResetProtectionCalled(); verifyRebootWipeUserDataMinimumArgsCalled(); @@ -198,6 +202,7 @@ public final class FactoryResetterTest { .build().factoryReset(); assertThat(success).isTrue(); + assertThat(isFactoryResetting()).isTrue(); verifyWipeAdoptableStorageCalled(); verifyWipeFactoryResetProtectionCalled(); verifyRebootWipeUserDataAllArgsCalled(); @@ -211,6 +216,7 @@ public final class FactoryResetterTest { .setSafetyChecker(mSafetyChecker).build().factoryReset(); assertThat(success).isFalse(); + assertThat(isFactoryResetting()).isTrue(); verifyWipeAdoptableStorageNotCalled(); verifyWipeFactoryResetProtectionNotCalled(); verifyRebootWipeUserDataNotCalled(); @@ -238,6 +244,7 @@ public final class FactoryResetterTest { .build().factoryReset(); assertThat(success).isFalse(); + assertThat(isFactoryResetting()).isTrue(); verifyWipeAdoptableStorageCalled(); verifyWipeFactoryResetProtectionCalled(); verifyRebootWipeUserDataAllArgsCalled(); diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index 8d6269c93764..617321beadd2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -178,7 +178,7 @@ public class LocalDisplayAdapterTest { // This should be public assertDisplayPrivateFlag(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), PORT_A, false); - // This should be public + // This should be private assertDisplayPrivateFlag(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), PORT_B, true); // This should be public diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt new file mode 100644 index 000000000000..c9598bdc8823 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/pm/DeletePackageHelperTest.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm + +import android.content.pm.PackageManager +import android.content.pm.UserInfo +import android.os.Build +import android.util.Log +import com.android.server.testutils.any +import com.android.server.testutils.spy +import com.android.server.testutils.whenever +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mockito.doAnswer + +@RunWith(JUnit4::class) +class DeletePackageHelperTest { + + @Rule + @JvmField + val rule = MockSystemRule() + + private lateinit var mPms: PackageManagerService + private lateinit var mUserManagerInternal: UserManagerInternal + + @Before + @Throws(Exception::class) + fun setup() { + Log.i("system.out", "setup", Exception()) + rule.system().stageNominalSystemState() + rule.system().stageScanExistingPackage( + "a.data.package", 1L, rule.system().dataAppDirectory) + + mUserManagerInternal = rule.mocks().injector.userManagerInternal + whenever(mUserManagerInternal.getUserIds()).thenReturn(intArrayOf(0, 1)) + + mPms = createPackageManagerService() + doAnswer { false }.`when`(mPms).isPackageDeviceAdmin(any(), any()) + doAnswer { null }.`when`(mPms).freezePackageForDelete(any(), any(), any(), any()) + } + + private fun createPackageManagerService(): PackageManagerService { + return spy(PackageManagerService(rule.mocks().injector, + false /*coreOnly*/, + false /*factoryTest*/, + MockSystem.DEFAULT_VERSION_INFO.fingerprint, + false /*isEngBuild*/, + false /*isUserDebugBuild*/, + Build.VERSION_CODES.CUR_DEVELOPMENT, + Build.VERSION.INCREMENTAL)) + } + + @Test + fun deleteSystemPackageFailsIfNotAdmin() { + val ps = mPms.mSettings.getPackageLPr("a.data.package") + whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true) + whenever(mUserManagerInternal.getUserInfo(1)).thenReturn(UserInfo(1, "test", 0)) + + val dph = DeletePackageHelper(mPms) + val result = dph.deletePackageX("a.data.package", 1L, 1, 0, false) + + assertThat(result).isEqualTo(PackageManager.DELETE_FAILED_USER_RESTRICTED) + } + + @Test + fun deleteSystemPackageSucceedsIfAdmin() { + val ps = mPms.mSettings.getPackageLPr("a.data.package") + whenever(PackageManagerServiceUtils.isSystemApp(ps)).thenReturn(true) + whenever(mUserManagerInternal.getUserInfo(1)).thenReturn( + UserInfo(1, "test", UserInfo.FLAG_ADMIN)) + + val dph = DeletePackageHelper(mPms) + val result = dph.deletePackageX("a.data.package", 1L, 1, + PackageManager.DELETE_SYSTEM_APP, false) + + assertThat(result).isEqualTo(PackageManager.DELETE_SUCCEEDED) + } +}
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java index 27637c2ba5d5..ed0336a5a4ea 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java @@ -21,6 +21,7 @@ import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_K import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD; +import static android.content.pm.PackageManager.FEATURE_WINDOW_MAGNIFICATION; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; @@ -42,6 +43,7 @@ import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Color; import android.provider.Settings; @@ -92,6 +94,8 @@ public class AccessibilityUserStateTest { @Mock private AccessibilityUserState.ServiceInfoChangeListener mMockListener; + @Mock private PackageManager mMockPackageManager; + @Mock private Context mMockContext; private MockContentResolver mMockResolver; @@ -113,6 +117,8 @@ public class AccessibilityUserStateTest { when(mMockServiceInfo.getComponentName()).thenReturn(COMPONENT_NAME); when(mMockConnection.getServiceInfo()).thenReturn(mMockServiceInfo); when(mMockContext.getResources()).thenReturn(resources); + when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); + when(mMockPackageManager.hasSystemFeature(FEATURE_WINDOW_MAGNIFICATION)).thenReturn(true); mFocusStrokeWidthDefaultValue = resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width); diff --git a/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java new file mode 100644 index 000000000000..ad2e7e4586ba --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.audio; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.media.AudioDeviceAttributes; +import android.media.AudioDeviceInfo; +import android.media.AudioDeviceVolumeManager; +import android.media.AudioManager; +import android.media.AudioSystem; +import android.media.IAudioDeviceVolumeDispatcher; +import android.media.VolumeInfo; +import android.os.RemoteException; +import android.os.test.TestLooper; + +import androidx.test.InstrumentationRegistry; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +public class AbsoluteVolumeBehaviorTest { + private static final String TAG = "AbsoluteVolumeBehaviorTest"; + + private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, ""); + + private Context mContext; + private String mPackageName; + private AudioSystemAdapter mSpyAudioSystem; + private SystemServerAdapter mSystemServer; + private SettingsAdapter mSettingsAdapter; + private TestLooper mTestLooper; + + private AudioService mAudioService; + + private IAudioDeviceVolumeDispatcher.Stub mMockDispatcher = + mock(IAudioDeviceVolumeDispatcher.Stub.class); + + @Before + public void setUp() throws Exception { + mTestLooper = new TestLooper(); + mContext = InstrumentationRegistry.getTargetContext(); + mPackageName = mContext.getOpPackageName(); + mSpyAudioSystem = spy(new NoOpAudioSystemAdapter()); + + mSystemServer = new NoOpSystemServerAdapter(); + mSettingsAdapter = new NoOpSettingsAdapter(); + mAudioService = new AudioService(mContext, mSpyAudioSystem, mSystemServer, + mSettingsAdapter, mTestLooper.getLooper()) { + @Override + public int getDeviceForStream(int stream) { + return AudioSystem.DEVICE_OUT_SPEAKER; + } + }; + + mTestLooper.dispatchAll(); + } + + @Test + public void registerDispatcher_setsVolumeBehaviorToAbsolute() { + List<VolumeInfo> volumes = Collections.singletonList( + new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build()); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true); + mTestLooper.dispatchAll(); + + assertThat(mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT)) + .isEqualTo(AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); + } + + @Test + public void registerDispatcher_setsVolume() { + List<VolumeInfo> volumes = Collections.singletonList( + new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setMinVolumeIndex(0) + .setMaxVolumeIndex(250) // Max index is 10 times that of STREAM_MUSIC + .setVolumeIndex(50) + .build()); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true); + mTestLooper.dispatchAll(); + + assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC)) + .isEqualTo(5); + } + + @Test + public void unregisterDispatcher_deviceBecomesVariableVolume_listenerNoLongerTriggered() + throws RemoteException { + + List<VolumeInfo> volumes = Collections.singletonList( + new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build()); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true); + mTestLooper.dispatchAll(); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(false, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true); + mTestLooper.dispatchAll(); + + assertThat(mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT)) + .isEqualTo(AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE); + + mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, 0, mPackageName); + mTestLooper.dispatchAll(); + + verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged( + eq(DEVICE_SPEAKER_OUT), any()); + } + + @Test + public void setDeviceVolumeBehavior_unregistersDispatcher() throws RemoteException { + List<VolumeInfo> volumes = Collections.singletonList( + new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build()); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true); + mTestLooper.dispatchAll(); + + mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT, + AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL, mPackageName); + mTestLooper.dispatchAll(); + + mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, 0, mPackageName); + mTestLooper.dispatchAll(); + + verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged( + eq(DEVICE_SPEAKER_OUT), any()); + } + + @Test + public void setStreamVolume_noAbsVolFlag_dispatchesVolumeChanged() throws RemoteException { + VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setMinVolumeIndex(0) + .setMaxVolumeIndex(250) // Max index is 10 times that of STREAM_MUSIC + .setVolumeIndex(50) + .build(); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, + Collections.singletonList(volumeInfo), true); + mTestLooper.dispatchAll(); + + // Set stream volume without FLAG_ABSOLUTE_VOLUME + mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, 0, mPackageName); + mTestLooper.dispatchAll(); + + // Dispatched volume index is scaled to the range in the initial VolumeInfo + verify(mMockDispatcher).dispatchDeviceVolumeChanged(DEVICE_SPEAKER_OUT, + new VolumeInfo.Builder(volumeInfo).setVolumeIndex(150).build()); + } + + @Test + public void setStreamVolume_absVolFlagSet_doesNotDispatchVolumeChanged() + throws RemoteException { + VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setMinVolumeIndex(0) + .setMaxVolumeIndex(250) + .setVolumeIndex(50) + .build(); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, + Collections.singletonList(volumeInfo), true); + mTestLooper.dispatchAll(); + + // Set stream volume with FLAG_ABSOLUTE_VOLUME + mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, + AudioManager.FLAG_ABSOLUTE_VOLUME, mPackageName); + mTestLooper.dispatchAll(); + + verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), + any()); + } + + @Test + public void adjustStreamVolume_handlesAdjust_noAbsVolFlag_noVolChange_dispatchesVolumeAdjusted() + throws RemoteException { + VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setMinVolumeIndex(0) + .setMaxVolumeIndex(250) + .setVolumeIndex(0) + .build(); + + // Register dispatcher with handlesVolumeAdjustment = true + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, + Collections.singletonList(volumeInfo), true); + mTestLooper.dispatchAll(); + + // Adjust stream volume without FLAG_ABSOLUTE_VOLUME + mAudioService.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, + 0, mPackageName); + mTestLooper.dispatchAll(); + + // Stream volume does not change + assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC)).isEqualTo(0); + // Listener is notified via dispatchDeviceVolumeAdjusted + verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), any()); + verify(mMockDispatcher).dispatchDeviceVolumeAdjusted(eq(DEVICE_SPEAKER_OUT), + argThat((VolumeInfo v) -> v.getStreamType() == AudioManager.STREAM_MUSIC), + eq(AudioManager.ADJUST_RAISE), eq(AudioDeviceVolumeManager.ADJUST_MODE_NORMAL)); + } + + @Test + public void adjustStreamVolume_noHandleAdjust_noAbsVolFlag_volChanges_dispatchesVolumeChanged() + throws RemoteException { + VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setMinVolumeIndex(0) + .setMaxVolumeIndex(250) + .setVolumeIndex(0) + .build(); + + // Register dispatcher with handlesVolumeAdjustment = false + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, + Collections.singletonList(volumeInfo), false); + mTestLooper.dispatchAll(); + + // Adjust stream volume without FLAG_ABSOLUTE_VOLUME + mAudioService.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, + 0, mPackageName); + mTestLooper.dispatchAll(); + + // Stream volume changes + assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC)).isNotEqualTo(0); + // Listener is notified via dispatchDeviceVolumeChanged + verify(mMockDispatcher).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), any()); + verify(mMockDispatcher, never()).dispatchDeviceVolumeAdjusted(eq(DEVICE_SPEAKER_OUT), any(), + anyInt(), anyInt()); + } + + @Test + public void adjustStreamVolume_absVolFlagSet_streamVolumeChanges_nothingDispatched() + throws RemoteException { + VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) + .setMinVolumeIndex(0) + .setMaxVolumeIndex(250) + .setVolumeIndex(0) + .build(); + + mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true, + mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, + Collections.singletonList(volumeInfo), true); + mTestLooper.dispatchAll(); + + // Adjust stream volume with FLAG_ABSOLUTE_VOLUME set + mAudioService.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, + AudioManager.FLAG_ABSOLUTE_VOLUME, mPackageName); + mTestLooper.dispatchAll(); + + // Stream volume changes + assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC)).isNotEqualTo(0); + // Nothing is dispatched + verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), any()); + verify(mMockDispatcher, never()).dispatchDeviceVolumeAdjusted(eq(DEVICE_SPEAKER_OUT), any(), + anyInt(), anyInt()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 484dc8450c57..197c21fad74a 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -8455,7 +8455,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { @Test public void testSendLostModeLocationUpdate_notOrganizationOwnedDevice() { - mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES); + mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); assertThrows(IllegalStateException.class, () -> dpm.sendLostModeLocationUpdate( getServices().executor, /* empty callback */ result -> {})); } @@ -8463,7 +8463,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { @Test public void testSendLostModeLocationUpdate_asDeviceOwner() throws Exception { final String TEST_PROVIDER = "network"; - mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES); + mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); setDeviceOwner(); when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER)); when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true); @@ -8480,7 +8480,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; - mContext.callerPermissions.add(permission.SEND_LOST_MODE_LOCATION_UPDATES); + mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER)); diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index 1fb58983607d..bf3c7c3e05fb 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -393,7 +393,8 @@ public class DisplayManagerServiceTest { displayDeviceInfo.displayCutout = new DisplayCutout( Insets.of(0, 10, 0, 0), zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect); - displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY; + displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY; + displayDeviceInfo.address = new TestUtils.TestDisplayAddress(); displayDevice.setDisplayDeviceInfo(displayDeviceInfo); displayManager.getDisplayDeviceRepository() .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); @@ -1307,7 +1308,8 @@ public class DisplayManagerServiceTest { displayDeviceInfo.displayCutout = new DisplayCutout( Insets.of(0, 10, 0, 0), zeroRect, new Rect(0, 0, 10, 10), zeroRect, zeroRect); - displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY; + displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY; + displayDeviceInfo.address = new TestUtils.TestDisplayAddress(); displayDevice.setDisplayDeviceInfo(displayDeviceInfo); displayManager.getDisplayDeviceRepository() .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED); diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index 86b6da0faad5..cc68ba88f76e 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -42,7 +42,6 @@ import android.content.res.Resources; import android.os.Handler; import android.os.IPowerManager; import android.os.IThermalService; -import android.os.Parcel; import android.os.PowerManager; import android.os.Process; import android.os.test.TestLooper; @@ -146,7 +145,7 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAddAndRemove_Internal() { DisplayDevice device = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); // add LogicalDisplay displayAdded = add(device); @@ -179,7 +178,7 @@ public class LogicalDisplayMapperTest { public void testDisplayDeviceAdd_TwoInternalOneDefault() { DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0); DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); LogicalDisplay display1 = add(device1); assertEquals(info(display1).address, info(device1).address); @@ -193,9 +192,9 @@ public class LogicalDisplayMapperTest { @Test public void testDisplayDeviceAdd_TwoInternalBothDefault() { DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); LogicalDisplay display1 = add(device1); assertEquals(info(display1).address, info(device1).address); @@ -208,9 +207,57 @@ public class LogicalDisplayMapperTest { } @Test + public void testDisplayDeviceAddAndRemove_OneExternalDefault() { + DisplayDevice device = createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + + // add + LogicalDisplay displayAdded = add(device); + assertEquals(info(displayAdded).address, info(device).address); + assertEquals(Display.DEFAULT_DISPLAY, id(displayAdded)); + + // remove + mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED); + verify(mListenerMock).onLogicalDisplayEventLocked( + mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED)); + LogicalDisplay displayRemoved = mDisplayCaptor.getValue(); + assertEquals(DEFAULT_DISPLAY, id(displayRemoved)); + assertEquals(displayAdded, displayRemoved); + } + + @Test + public void testDisplayDeviceAddAndRemove_SwitchDefault() { + DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); + + LogicalDisplay display1 = add(device1); + assertEquals(info(display1).address, info(device1).address); + assertEquals(DEFAULT_DISPLAY, id(display1)); + + LogicalDisplay display2 = add(device2); + assertEquals(info(display2).address, info(device2).address); + // We can only have one default display + assertEquals(DEFAULT_DISPLAY, id(display1)); + + // remove + mDisplayDeviceRepo.onDisplayDeviceEvent(device1, DISPLAY_DEVICE_EVENT_REMOVED); + + verify(mListenerMock).onLogicalDisplayEventLocked( + mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED)); + LogicalDisplay displayRemoved = mDisplayCaptor.getValue(); + // Display 1 is still the default logical display + assertEquals(DEFAULT_DISPLAY, id(display1)); + // The logical displays had their devices swapped and Display 2 was removed + assertEquals(display2, displayRemoved); + assertEquals(info(display1).address, info(device2).address); + } + + @Test public void testGetDisplayIdsLocked() { add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, 0)); add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0)); @@ -223,19 +270,19 @@ public class LogicalDisplayMapperTest { @Test public void testGetDisplayInfoForStateLocked_oneDisplayGroup_internalType() { add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_INTERNAL, 700, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked( DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP); - assertThat(displayInfos.size()).isEqualTo(3); + assertThat(displayInfos.size()).isEqualTo(1); for (DisplayInfo displayInfo : displayInfos) { assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY); assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP); - assertThat(displayInfo.logicalWidth).isAnyOf(600, 200, 700); + assertThat(displayInfo.logicalWidth).isEqualTo(600); assertThat(displayInfo.logicalHeight).isEqualTo(800); } } @@ -243,19 +290,19 @@ public class LogicalDisplayMapperTest { @Test public void testGetDisplayInfoForStateLocked_oneDisplayGroup_differentTypes() { add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_EXTERNAL, 700, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked( DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP); - assertThat(displayInfos.size()).isEqualTo(2); + assertThat(displayInfos.size()).isEqualTo(1); for (DisplayInfo displayInfo : displayInfos) { assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY); assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP); - assertThat(displayInfo.logicalWidth).isAnyOf(600, 200); + assertThat(displayInfo.logicalWidth).isEqualTo(600); assertThat(displayInfo.logicalHeight).isEqualTo(800); } } @@ -263,19 +310,19 @@ public class LogicalDisplayMapperTest { @Test public void testGetDisplayInfoForStateLocked_multipleDisplayGroups_defaultGroup() { add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); add(createDisplayDevice(Display.TYPE_VIRTUAL, 700, 800, DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP)); Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked( DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP); - assertThat(displayInfos.size()).isEqualTo(2); + assertThat(displayInfos.size()).isEqualTo(1); for (DisplayInfo displayInfo : displayInfos) { assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY); assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP); - assertThat(displayInfo.logicalWidth).isAnyOf(600, 200); + assertThat(displayInfo.logicalWidth).isEqualTo(600); assertThat(displayInfo.logicalHeight).isEqualTo(800); } } @@ -283,7 +330,7 @@ public class LogicalDisplayMapperTest { @Test public void testSingleDisplayGroup() { LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0)); LogicalDisplay display3 = add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0)); @@ -298,7 +345,7 @@ public class LogicalDisplayMapperTest { @Test public void testMultipleDisplayGroups() { LogicalDisplay display1 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, - DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY)); + DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY)); LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0)); @@ -371,7 +418,7 @@ public class LogicalDisplayMapperTest { ///////////////// private TestDisplayDevice createDisplayDevice(int type, int width, int height, int flags) { - return createDisplayDevice(new DisplayAddressImpl(), type, width, height, flags); + return createDisplayDevice(new TestUtils.TestDisplayAddress(), type, width, height, flags); } private TestDisplayDevice createDisplayDevice( @@ -385,7 +432,7 @@ public class LogicalDisplayMapperTest { displayDeviceInfo.supportedModes = new Display.Mode[1]; displayDeviceInfo.supportedModes[0] = new Display.Mode(1, width, height, 60f); displayDeviceInfo.modeId = 1; - displayDeviceInfo.address = new DisplayAddressImpl(); + displayDeviceInfo.address = address; return device; } @@ -427,18 +474,8 @@ public class LogicalDisplayMapperTest { assertNotEquals(DEFAULT_DISPLAY, id(displayRemoved)); } - /** - * Create a custom {@link DisplayAddress} to ensure we're not relying on any specific - * display-address implementation in our code. Intentionally uses default object (reference) - * equality rules. - */ - class DisplayAddressImpl extends DisplayAddress { - @Override - public void writeToParcel(Parcel out, int flags) { } - } - class TestDisplayDevice extends DisplayDevice { - private DisplayDeviceInfo mInfo = new DisplayDeviceInfo(); + private DisplayDeviceInfo mInfo; private DisplayDeviceInfo mSentInfo; TestDisplayDevice() { diff --git a/services/tests/servicestests/src/com/android/server/display/TestUtils.java b/services/tests/servicestests/src/com/android/server/display/TestUtils.java index 859dfe3c3fa4..0454587bfefe 100644 --- a/services/tests/servicestests/src/com/android/server/display/TestUtils.java +++ b/services/tests/servicestests/src/com/android/server/display/TestUtils.java @@ -18,7 +18,9 @@ package com.android.server.display; import android.hardware.Sensor; import android.hardware.SensorEvent; +import android.os.Parcel; import android.os.SystemClock; +import android.view.DisplayAddress; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -57,4 +59,13 @@ public final class TestUtils { return sensor; } + /** + * Create a custom {@link DisplayAddress} to ensure we're not relying on any specific + * display-address implementation in our code. Intentionally uses default object (reference) + * equality rules. + */ + public static class TestDisplayAddress extends DisplayAddress { + @Override + public void writeToParcel(Parcel out, int flags) { } + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/GiveFeaturesActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/GiveFeaturesActionTest.java deleted file mode 100644 index 0b31db69f0a9..000000000000 --- a/services/tests/servicestests/src/com/android/server/hdmi/GiveFeaturesActionTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.hdmi; - -import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORTED; -import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORT_UNKNOWN; -import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_VERSION_2_0; -import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; - -import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.spy; - -import android.content.Context; -import android.content.ContextWrapper; -import android.hardware.hdmi.DeviceFeatures; -import android.hardware.hdmi.HdmiControlManager; -import android.hardware.hdmi.HdmiDeviceInfo; -import android.hardware.hdmi.IHdmiControlCallback; -import android.os.Looper; -import android.os.RemoteException; -import android.os.test.TestLooper; -import android.platform.test.annotations.Presubmit; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; - -import com.android.server.SystemService; - -import com.google.android.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; - -@SmallTest -@Presubmit -@RunWith(JUnit4.class) -public class GiveFeaturesActionTest { - private HdmiControlService mHdmiControlServiceSpy; - private HdmiCecController mHdmiCecController; - private HdmiCecLocalDevicePlayback mPlaybackDevice; - private FakeNativeWrapper mNativeWrapper; - private FakePowerManagerWrapper mPowerManager; - private Looper mLooper; - private Context mContextSpy; - private TestLooper mTestLooper = new TestLooper(); - private int mPhysicalAddress = 0x1100; - private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); - private int mPlaybackLogicalAddress; - - private TestCallback mTestCallback; - private GiveFeaturesAction mAction; - - /** - * Setup: Local Playback device queries the features of a connected TV. - */ - @Before - public void setUp() throws RemoteException { - mContextSpy = spy(new ContextWrapper( - InstrumentationRegistry.getInstrumentation().getTargetContext())); - - mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, Collections.emptyList())); - doNothing().when(mHdmiControlServiceSpy) - .writeStringSystemProperty(anyString(), anyString()); - - mLooper = mTestLooper.getLooper(); - mHdmiControlServiceSpy.setIoLooper(mLooper); - mHdmiControlServiceSpy.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy)); - - mNativeWrapper = new FakeNativeWrapper(); - mNativeWrapper.setPhysicalAddress(mPhysicalAddress); - - mHdmiCecController = HdmiCecController.createWithNativeWrapper( - mHdmiControlServiceSpy, mNativeWrapper, mHdmiControlServiceSpy.getAtomWriter()); - mHdmiControlServiceSpy.setCecController(mHdmiCecController); - mHdmiControlServiceSpy.setHdmiMhlController( - HdmiMhlControllerStub.create(mHdmiControlServiceSpy)); - mHdmiControlServiceSpy.initService(); - mPowerManager = new FakePowerManagerWrapper(mContextSpy); - mHdmiControlServiceSpy.setPowerManager(mPowerManager); - - mPlaybackDevice = new HdmiCecLocalDevicePlayback(mHdmiControlServiceSpy); - mPlaybackDevice.init(); - mLocalDevices.add(mPlaybackDevice); - - mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC); - mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); - mTestLooper.dispatchAll(); - - synchronized (mPlaybackDevice.mLock) { - mPlaybackLogicalAddress = mPlaybackDevice.getDeviceInfo().getLogicalAddress(); - } - - // Setup specific to these tests - mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( - Constants.ADDR_TV, 0x0000, HdmiDeviceInfo.DEVICE_TV)); - mTestLooper.dispatchAll(); - - mTestCallback = new TestCallback(); - mAction = new GiveFeaturesAction(mPlaybackDevice, Constants.ADDR_TV, mTestCallback); - } - - @Test - public void sendsGiveFeaturesMessage() { - mPlaybackDevice.addAndStartAction(mAction); - mTestLooper.dispatchAll(); - - HdmiCecMessage giveFeatures = HdmiCecMessageBuilder.buildGiveFeatures( - mPlaybackLogicalAddress, Constants.ADDR_TV); - assertThat(mNativeWrapper.getResultMessages()).contains(giveFeatures); - } - - @Test - public void noMatchingReportFeaturesReceived_actionFailsAndNetworkIsNotUpdated() { - mPlaybackDevice.addAndStartAction(mAction); - mTestLooper.dispatchAll(); - - // Wrong source - mNativeWrapper.onCecMessage(ReportFeaturesMessage.build( - Constants.ADDR_AUDIO_SYSTEM, HdmiControlManager.HDMI_CEC_VERSION_2_0, - Arrays.asList(DEVICE_AUDIO_SYSTEM), Constants.RC_PROFILE_SOURCE, - Collections.emptyList(), DeviceFeatures.NO_FEATURES_SUPPORTED)); - mTestLooper.dispatchAll(); - - mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS); - mTestLooper.dispatchAll(); - - @DeviceFeatures.FeatureSupportStatus int avcSupport = - mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) - .getDeviceFeatures().getSetAudioVolumeLevelSupport(); - - assertThat(avcSupport).isEqualTo(FEATURE_SUPPORT_UNKNOWN); - assertThat(mTestCallback.getResult()).isEqualTo( - HdmiControlManager.RESULT_COMMUNICATION_FAILED); - } - - @Test - public void matchingReportFeaturesReceived_actionSucceedsAndNetworkIsUpdated() { - mPlaybackDevice.addAndStartAction(mAction); - mTestLooper.dispatchAll(); - - mNativeWrapper.onCecMessage( - ReportFeaturesMessage.build( - Constants.ADDR_TV, HDMI_CEC_VERSION_2_0, Collections.emptyList(), - Constants.RC_PROFILE_TV, Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), - DeviceFeatures.NO_FEATURES_SUPPORTED.toBuilder() - .setSetAudioVolumeLevelSupport(FEATURE_SUPPORTED) - .build() - ) - ); - mTestLooper.dispatchAll(); - - @DeviceFeatures.FeatureSupportStatus int avcSupport = - mHdmiControlServiceSpy.getHdmiCecNetwork().getCecDeviceInfo(Constants.ADDR_TV) - .getDeviceFeatures().getSetAudioVolumeLevelSupport(); - - assertThat(avcSupport).isEqualTo(FEATURE_SUPPORTED); - assertThat(mTestCallback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS); - } - - private static class TestCallback extends IHdmiControlCallback.Stub { - private final ArrayList<Integer> mCallbackResult = new ArrayList<Integer>(); - - @Override - public void onComplete(int result) { - mCallbackResult.add(result); - } - - private int getResult() { - assertThat(mCallbackResult.size()).isEqualTo(1); - return mCallbackResult.get(0); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index b2f506a5b1f9..89450ffbc11d 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -210,6 +210,8 @@ public class PowerManagerServiceTest { Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); + Settings.Secure.putInt(mContextSpy.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0); mClock = new OffsettableClock.Stopped(); mTestLooper = new TestLooper(mClock::now); @@ -709,6 +711,48 @@ public class PowerManagerServiceTest { assertThat(mService.getBinderServiceInstance().forceSuspend()).isFalse(); } + @SuppressWarnings("GuardedBy") + @Test + public void testScreensaverActivateOnSleepDisabled_powered_afterTimeout_goesToDozing() { + when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true); + + doAnswer(inv -> { + when(mDreamManagerInternalMock.isDreaming()).thenReturn(true); + return null; + }).when(mDreamManagerInternalMock).startDream(anyBoolean()); + + setMinimumScreenOffTimeoutConfig(5); + createService(); + startSystem(); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + + advanceTime(15000); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING); + } + + @SuppressWarnings("GuardedBy") + @Test + public void testScreensaverActivateOnSleepEnabled_powered_afterTimeout_goesToDreaming() { + when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(true); + Settings.Secure.putInt(mContextSpy.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1); + + doAnswer(inv -> { + when(mDreamManagerInternalMock.isDreaming()).thenReturn(true); + return null; + }).when(mDreamManagerInternalMock).startDream(anyBoolean()); + + setMinimumScreenOffTimeoutConfig(5); + createService(); + startSystem(); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); + + advanceTime(15000); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING); + } + @Test public void testSetDozeOverrideFromDreamManager_triggersSuspendBlocker() { final String suspendBlockerName = "PowerManagerService.Display"; @@ -1042,6 +1086,23 @@ public class PowerManagerServiceTest { assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_ASLEEP); } + + @SuppressWarnings("GuardedBy") + @Test + public void testInattentiveSleep_goesToSleepFromDream() { + setAttentiveTimeout(20000); + createService(); + startSystem(); + setPluggedIn(true); + forceAwake(); + forceDream(); + when(mDreamManagerInternalMock.isDreaming()).thenReturn(true); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING); + + advanceTime(20500); + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); + } + @Test public void testWakeLock_affectsProperDisplayGroup() { final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; @@ -1136,6 +1197,11 @@ public class PowerManagerServiceTest { info.displayGroupId = nonDefaultDisplayGroupId; when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info); + doAnswer(inv -> { + when(mDreamManagerInternalMock.isDreaming()).thenReturn(true); + return null; + }).when(mDreamManagerInternalMock).startDream(anyBoolean()); + final String pkg = mContextSpy.getOpPackageName(); final Binder token = new Binder(); final String tag = "testRemovedDisplayGroupWakeLock_affectsNoDisplayGroups"; diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 210d2faf44d6..17464a6551d4 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -512,8 +512,30 @@ public class AppStandbyControllerTests { return controller; } - private long getCurrentTime() { - return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + private void setupInitialUsageHistory() throws Exception { + final int[] userIds = new int[] { USER_ID, USER_ID2, USER_ID3 }; + final String[] packages = new String[] { + PACKAGE_1, + PACKAGE_2, + PACKAGE_EXEMPTED_1, + PACKAGE_SYSTEM_HEADFULL, + PACKAGE_SYSTEM_HEADLESS, + PACKAGE_WELLBEING, + PACKAGE_BACKGROUND_LOCATION, + ADMIN_PKG, + ADMIN_PKG2, + ADMIN_PKG3 + }; + for (int userId : userIds) { + for (String pkg : packages) { + final AppIdleHistory.AppUsageHistory usageHistory = mController + .getAppIdleHistoryForTest().getAppUsageHistory( + pkg, userId, mInjector.mElapsedRealtime); + usageHistory.lastUsedElapsedTime = 0; + usageHistory.lastUsedByUserElapsedTime = 0; + usageHistory.lastUsedScreenTime = 0; + } + } } @Before @@ -524,6 +546,7 @@ public class AppStandbyControllerTests { MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext()); mInjector = new MyInjector(myContext, Looper.getMainLooper()); mController = setupController(); + setupInitialUsageHistory(); } @After diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java index 5458a5b84eea..ff6c9769b69f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java @@ -20,6 +20,7 @@ import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -53,7 +54,7 @@ import java.util.Map; public class GroupHelperTest extends UiServiceTestCase { private @Mock GroupHelper.Callback mCallback; - private final static int AUTOGROUP_AT_COUNT = 4; + private final static int AUTOGROUP_AT_COUNT = 7; private GroupHelper mGroupHelper; @Before @@ -88,7 +89,7 @@ public class GroupHelperTest extends UiServiceTestCase { false); } verify(mCallback, never()).addAutoGroupSummary( - eq(UserHandle.USER_SYSTEM), eq(pkg), anyString()); + eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean()); verify(mCallback, never()).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -105,7 +106,7 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationPosted( getSbn(pkg2, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM), false); verify(mCallback, never()).addAutoGroupSummary( - eq(UserHandle.USER_SYSTEM), eq(pkg), anyString()); + eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean()); verify(mCallback, never()).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -120,7 +121,8 @@ public class GroupHelperTest extends UiServiceTestCase { } mGroupHelper.onNotificationPosted( getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.ALL), false); - verify(mCallback, never()).addAutoGroupSummary(anyInt(), eq(pkg), anyString()); + verify(mCallback, never()).addAutoGroupSummary( + anyInt(), eq(pkg), anyString(), anyBoolean()); verify(mCallback, never()).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -136,13 +138,12 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationPosted( getSbn(pkg, AUTOGROUP_AT_COUNT, "four", UserHandle.SYSTEM, "a"), false); verify(mCallback, never()).addAutoGroupSummary( - eq(UserHandle.USER_SYSTEM), eq(pkg), anyString()); + eq(UserHandle.USER_SYSTEM), eq(pkg), anyString(), anyBoolean()); verify(mCallback, never()).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); } - @Test public void testPostingOverLimit() throws Exception { final String pkg = "package"; @@ -150,7 +151,23 @@ public class GroupHelperTest extends UiServiceTestCase { mGroupHelper.onNotificationPosted( getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM), false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString()); + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false)); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + } + + @Test + public void testPostingOverLimit_addsOngoingFlag() throws Exception { + final String pkg = "package"; + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM); + if (i == 0) { + sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; + } + mGroupHelper.onNotificationPosted(sbn, false); + } + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(true)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -178,7 +195,7 @@ public class GroupHelperTest extends UiServiceTestCase { int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT + 1); + userId, pkg), AUTOGROUP_AT_COUNT + 1); } @Test @@ -199,15 +216,14 @@ public class GroupHelperTest extends UiServiceTestCase { } notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT; - - mGroupHelper.onNotificationUpdated(notifications.get(0), true); + mGroupHelper.onNotificationUpdated(notifications.get(0)); verify(mCallback, times(AUTOGROUP_AT_COUNT + 2)) .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT); + userId, pkg), AUTOGROUP_AT_COUNT); } @Test @@ -229,18 +245,18 @@ public class GroupHelperTest extends UiServiceTestCase { notifications.get(0).getNotification().flags &= ~Notification.FLAG_ONGOING_EVENT; - mGroupHelper.onNotificationUpdated(notifications.get(0), true); + mGroupHelper.onNotificationUpdated(notifications.get(0)); notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - mGroupHelper.onNotificationUpdated(notifications.get(0), true); + mGroupHelper.onNotificationUpdated(notifications.get(0)); verify(mCallback, times(AUTOGROUP_AT_COUNT + 3)) .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT + 1); + userId, pkg), AUTOGROUP_AT_COUNT + 1); } @Test @@ -267,7 +283,7 @@ public class GroupHelperTest extends UiServiceTestCase { int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg, AUTOGROUP_KEY), AUTOGROUP_AT_COUNT); + userId, pkg), AUTOGROUP_AT_COUNT); } @@ -288,14 +304,14 @@ public class GroupHelperTest extends UiServiceTestCase { } notifications.get(0).getNotification().flags |= Notification.FLAG_ONGOING_EVENT; - mGroupHelper.onNotificationUpdated(notifications.get(0), true); + mGroupHelper.onNotificationUpdated(notifications.get(0)); verify(mCallback, times(1)) .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg, AUTOGROUP_KEY), 1); + userId, pkg), 1); } @Test @@ -305,7 +321,7 @@ public class GroupHelperTest extends UiServiceTestCase { for (int i = 0; i < AUTOGROUP_AT_COUNT + 1; i++) { notifications.add(getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM)); } - StatusBarNotification sbn = notifications.get(0); + StatusBarNotification sbn = notifications.get(AUTOGROUP_AT_COUNT); sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; sbn.setOverrideGroupKey(AUTOGROUP_KEY); @@ -319,7 +335,7 @@ public class GroupHelperTest extends UiServiceTestCase { int userId = UserHandle.SYSTEM.getIdentifier(); assertEquals(mGroupHelper.getOngoingGroupCount( - userId, pkg, AUTOGROUP_KEY), 1); + userId, pkg), 1); } @Test @@ -342,7 +358,7 @@ public class GroupHelperTest extends UiServiceTestCase { .updateAutogroupSummary(anyInt(), anyString(), eq(true)); int userId = UserHandle.SYSTEM.getIdentifier(); - assertEquals(mGroupHelper.getOngoingGroupCount(userId, pkg, AUTOGROUP_KEY), 0); + assertEquals(mGroupHelper.getOngoingGroupCount(userId, pkg), 0); } @@ -355,7 +371,7 @@ public class GroupHelperTest extends UiServiceTestCase { posted.add(sbn); mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString()); + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -382,28 +398,22 @@ public class GroupHelperTest extends UiServiceTestCase { posted.add(sbn); mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString()); + verify(mCallback, times(1)).addAutoGroupSummary( + anyInt(), eq(pkg), anyString(), anyBoolean()); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); Mockito.reset(mCallback); - int i = 0; - for (i = 0; i < AUTOGROUP_AT_COUNT - 2; i++) { - final StatusBarNotification sbn = - getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group"); - mGroupHelper.onNotificationPosted(sbn, false); - } - verify(mCallback, times(AUTOGROUP_AT_COUNT - 2)).removeAutoGroup(anyString()); - verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); - Mockito.reset(mCallback); - - for (; i < AUTOGROUP_AT_COUNT; i++) { + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { final StatusBarNotification sbn = getSbn(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "app group"); mGroupHelper.onNotificationPosted(sbn, false); + verify(mCallback, times(1)).removeAutoGroup(sbn.getKey()); + if (i < AUTOGROUP_AT_COUNT -1) { + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); + } } - verify(mCallback, times(2)).removeAutoGroup(anyString()); verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), anyString()); } @@ -417,7 +427,7 @@ public class GroupHelperTest extends UiServiceTestCase { posted.add(sbn); mGroupHelper.onNotificationPosted(sbn, false); } - verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString()); + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(false)); verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); @@ -441,7 +451,7 @@ public class GroupHelperTest extends UiServiceTestCase { final StatusBarNotification sbn = getSbn(pkg, 5, String.valueOf(5), UserHandle.SYSTEM); posted.add(sbn); mGroupHelper.onNotificationPosted(sbn, true); - verify(mCallback, times(posted.size())).addAutoGroup(anyString()); + verify(mCallback, times(1)).addAutoGroup(sbn.getKey()); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString()); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java index d4420bd86fc1..f4b9e258f7e0 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java @@ -27,8 +27,13 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.INotificationManager; @@ -38,8 +43,10 @@ import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.pm.VersionedPackage; import android.os.Bundle; +import android.os.UserHandle; import android.service.notification.NotificationListenerFilter; import android.service.notification.NotificationListenerService; +import android.testing.TestableContext; import android.util.ArraySet; import android.util.Pair; import android.util.TypedXmlPullParser; @@ -69,6 +76,7 @@ public class NotificationListenersTest extends UiServiceTestCase { NotificationManagerService mNm; @Mock private INotificationManager mINm; + private TestableContext mContext = spy(getContext()); NotificationManagerService.NotificationListeners mListeners; @@ -80,6 +88,7 @@ public class NotificationListenersTest extends UiServiceTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); getContext().setMockPackageManager(mPm); + doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); mListeners = spy(mNm.new NotificationListeners( mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm)); @@ -370,4 +379,13 @@ public class NotificationListenersTest extends UiServiceTestCase { assertFalse(mListeners.hasAllowedListener(mCn2.getPackageName(), uid1)); assertFalse(mListeners.hasAllowedListener(mCn2.getPackageName(), uid2)); } + + @Test + public void testBroadcastUsers() { + int userId = 0; + mListeners.setPackageOrComponentEnabled(mCn1.flattenToString(), userId, true, false, true); + + verify(mContext).sendBroadcastAsUser( + any(), eq(UserHandle.of(userId)), nullable(String.class)); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java index 2ba587d21163..0f6d5a56c667 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java @@ -722,7 +722,7 @@ public class NotificationPermissionMigrationTest extends UiServiceTestCase { when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true); NotificationRecord r = mService.createAutoGroupSummary( - temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey()); + temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), false); assertThat(r.isImportanceFixed()).isTrue(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java index 66da2a631868..716612c70aef 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java @@ -284,7 +284,7 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { .setCreateActivity(true).build().getTopMostActivity(); activity2.getTask().setResumedActivity(activity2, "test"); - mAtm.mAmInternal.deletePendingTopUid(activity1.getUid()); + mAtm.mAmInternal.deletePendingTopUid(activity1.getUid(), Long.MAX_VALUE); clearInvocations(mAtm); activity1.moveFocusableActivityToTop("test"); assertTrue(mAtm.mAmInternal.isPendingTopUid(activity1.getUid())); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 94f900efb845..97d477f2bae9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -1064,6 +1064,47 @@ public class AppTransitionControllerTest extends WindowTestsBase { verify(activity2).setDropInputMode(DropInputMode.NONE); } + /** + * Since we don't have any use case to rely on handling input during animation, disable it even + * if it is trusted embedding so that it could cover some edge-cases when a previously trusted + * host starts doing something bad. + */ + @Test + public void testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation() { + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); + + // Create a TaskFragment with only trusted embedded activity + final Task task = createTask(mDisplayContent); + final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) + .setParentTask(task) + .createActivityCount(1) + .setOrganizer(organizer) + .build(); + final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord(); + prepareActivityForAppTransition(activity); + doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity); + spyOn(mDisplayContent.mAppTransition); + + // Prepare and start transition. + prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); + mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); + + // The animation will be animated remotely by client and all activities are input disabled + // for untrusted animation. + assertTrue(remoteAnimationRunner.isAnimationStarted()); + verify(activity).setDropInputForAnimation(true); + verify(activity).setDropInputMode(DropInputMode.ALL); + + // Reset input after animation is finished. + clearInvocations(activity); + remoteAnimationRunner.finishAnimation(); + + verify(activity).setDropInputForAnimation(false); + verify(activity).setDropInputMode(DropInputMode.NONE); + } + @Test public void testTransitionGoodToGoForTaskFragments() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java index 70d71bc627c0..7409d62e175e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -31,13 +31,13 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; import android.app.ActivityManager; -import android.window.TaskSnapshot; import android.content.res.Configuration; import android.graphics.Rect; import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; import android.view.Surface; +import android.window.TaskSnapshot; import androidx.test.filters.MediumTest; @@ -83,6 +83,12 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa assertEquals(TEST_INSETS, snapshot.getContentInsets()); assertNotNull(snapshot.getSnapshot()); assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation()); + + snapshot.getHardwareBuffer().close(); + mPersister.persistSnapshot(1, mTestUserId, snapshot); + mPersister.waitForQueueEmpty(); + assertTrueForFiles(files, file -> !file.exists(), + " snapshot files must be removed by invalid buffer"); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java index 437d41885684..f71ed2f08a22 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -131,8 +131,7 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { } TaskSnapshot createSnapshot() { - return new TaskSnapshotBuilder() - .build(); + return new TaskSnapshotBuilder().setTopActivityComponent(getUniqueComponentName()).build(); } protected static void assertTrueForFiles(File[] files, Predicate<File> predicate, diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 6e0d8549defc..bcab4a5cde27 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -903,7 +903,7 @@ class WindowTestsBase extends SystemServiceTestsBase { doReturn(100).when(hardwareBuffer).getHeight(); } - private static ComponentName getUniqueComponentName() { + static ComponentName getUniqueComponentName() { return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++); } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 366ab0968bb8..da54c329d5be 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -79,6 +79,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; @@ -1982,6 +1983,10 @@ public class UsageStatsService extends SystemService implements } } + void clearLastUsedTimestamps(@NonNull String packageName, @UserIdInt int userId) { + mAppStandby.clearLastUsedTimestampsForTest(packageName, userId); + } + private final class BinderService extends IUsageStatsManager.Stub { private boolean hasPermission(String callingPackage) { @@ -2816,6 +2821,14 @@ public class UsageStatsService extends SystemService implements } return mAppStandby.getAppStandbyConstant(key); } + + @Override + public int handleShellCommand(@NonNull ParcelFileDescriptor in, + @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, + @NonNull String[] args) { + return new UsageStatsShellCommand(UsageStatsService.this).exec(this, + in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args); + } } void registerAppUsageObserver(int callingUid, int observerId, String[] packages, diff --git a/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java b/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java new file mode 100644 index 000000000000..772b22a2b179 --- /dev/null +++ b/services/usage/java/com/android/server/usage/UsageStatsShellCommand.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.usage; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.os.ShellCommand; +import android.os.UserHandle; + +import java.io.PrintWriter; + +class UsageStatsShellCommand extends ShellCommand { + private final UsageStatsService mService; + + UsageStatsShellCommand(UsageStatsService usageStatsService) { + mService = usageStatsService; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(null); + } + switch (cmd) { + case "clear-last-used-timestamps": + return runClearLastUsedTimestamps(); + default: + return handleDefaultCommands(cmd); + } + } + + @Override + public void onHelp() { + final PrintWriter pw = getOutPrintWriter(); + pw.println("UsageStats service (usagestats) commands:"); + pw.println("help"); + pw.println(" Print this help text."); + pw.println(); + pw.println("clear-last-used-timestamps PACKAGE_NAME [-u | --user USER_ID]"); + pw.println(" Clears any existing usage data for the given package."); + pw.println(); + } + + @SuppressLint("AndroidFrameworkRequiresPermission") + private int runClearLastUsedTimestamps() { + final String packageName = getNextArgRequired(); + + int userId = UserHandle.USER_CURRENT; + String opt; + while ((opt = getNextOption()) != null) { + if ("-u".equals(opt) || "--user".equals(opt)) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else { + getErrPrintWriter().println("Error: unknown option: " + opt); + return -1; + } + } + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + mService.clearLastUsedTimestamps(packageName, userId); + return 0; + } +} diff --git a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java index 0fa79df3e008..04c52f7253e9 100644 --- a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java +++ b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java @@ -84,7 +84,7 @@ public final class UsbDirectMidiDevice implements Closeable { private final Object mLock = new Object(); private boolean mIsOpen; - private final UsbMidiPacketConverter mUsbMidiPacketConverter = new UsbMidiPacketConverter(); + private UsbMidiPacketConverter mUsbMidiPacketConverter; private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() { @@ -264,6 +264,11 @@ public final class UsbDirectMidiDevice implements Closeable { Log.d(TAG, "openLocked()"); UsbManager manager = mContext.getSystemService(UsbManager.class); + // Converting from raw MIDI to USB MIDI is not thread-safe. + // UsbMidiPacketConverter creates a converter from raw MIDI + // to USB MIDI for each USB output. + mUsbMidiPacketConverter = new UsbMidiPacketConverter(mNumOutputs); + mUsbDeviceConnections = new ArrayList<UsbDeviceConnection>(mUsbInterfaces.size()); mInputUsbEndpoints = new ArrayList<ArrayList<UsbEndpoint>>(mUsbInterfaces.size()); mOutputUsbEndpoints = new ArrayList<ArrayList<UsbEndpoint>>(mUsbInterfaces.size()); @@ -415,7 +420,7 @@ public final class UsbDirectMidiDevice implements Closeable { } else { convertedArray = mUsbMidiPacketConverter.rawMidiToUsbMidi( - event.data, event.count); + event.data, event.count, portFinal); } if (DEBUG) { @@ -518,6 +523,8 @@ public final class UsbDirectMidiDevice implements Closeable { mInputUsbEndpoints = null; mOutputUsbEndpoints = null; + mUsbMidiPacketConverter = null; + mIsOpen = false; } diff --git a/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java b/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java index 7c93c7668fa2..56bb23681741 100644 --- a/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java +++ b/services/usb/java/com/android/server/usb/UsbMidiPacketConverter.java @@ -74,8 +74,15 @@ public class UsbMidiPacketConverter { private static final byte SYSEX_START_EXCLUSIVE = (byte) 0xF0; private static final byte SYSEX_END_EXCLUSIVE = (byte) 0xF7; - private UsbMidiEncoder mUsbMidiEncoder = new UsbMidiEncoder(); private UsbMidiDecoder mUsbMidiDecoder = new UsbMidiDecoder(); + private UsbMidiEncoder[] mUsbMidiEncoders; + + public UsbMidiPacketConverter(int numEncoders) { + mUsbMidiEncoders = new UsbMidiEncoder[numEncoders]; + for (int i = 0; i < numEncoders; i++) { + mUsbMidiEncoders[i] = new UsbMidiEncoder(); + } + } /** * Converts a USB MIDI array into a raw MIDI array. @@ -93,10 +100,11 @@ public class UsbMidiPacketConverter { * * @param midiBytes the raw MIDI bytes to convert * @param size the size of usbMidiBytes + * @param encoderId which encoder to use * @return byte array of USB MIDI packets */ - public byte[] rawMidiToUsbMidi(byte[] midiBytes, int size) { - return mUsbMidiEncoder.encode(midiBytes, size); + public byte[] rawMidiToUsbMidi(byte[] midiBytes, int size, int encoderId) { + return mUsbMidiEncoders[encoderId].encode(midiBytes, size); } private class UsbMidiDecoder { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index d527a230a97b..c86f38d4264d 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -679,6 +679,7 @@ final class HotwordDetectionConnection { private void restartProcessLocked() { Slog.v(TAG, "Restarting hotword detection process"); ServiceConnection oldConnection = mRemoteHotwordDetectionService; + HotwordDetectionServiceIdentity previousIdentity = mIdentity; // TODO(volnov): this can be done after connect() has been successful. if (mValidatingDspTrigger) { @@ -722,6 +723,9 @@ final class HotwordDetectionConnection { } oldConnection.ignoreConnectionStatusEvents(); oldConnection.unbind(); + if (previousIdentity != null) { + removeServiceUidForAudioPolicy(previousIdentity.getIsolatedUid()); + } } static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub { diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java index 730a9d183b8f..2d0135ae1c99 100644 --- a/telephony/java/android/telephony/ModemActivityInfo.java +++ b/telephony/java/android/telephony/ModemActivityInfo.java @@ -383,8 +383,6 @@ public final class ModemActivityInfo implements Parcelable { * activity. */ public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) { - int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS]; - ActivityStatsTechSpecificInfo[] mDeltaSpecificInfo; mDeltaSpecificInfo = new ActivityStatsTechSpecificInfo[other.getSpecificInfoLength()]; @@ -399,6 +397,7 @@ public final class ModemActivityInfo implements Parcelable { if (other.mActivityStatsTechSpecificInfo[i].getFrequencyRange() == mActivityStatsTechSpecificInfo[j].getFrequencyRange()) { int freq = mActivityStatsTechSpecificInfo[j].getFrequencyRange(); + int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS]; for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) { txTimeMs[lvl] = (int) (other.getTransmitDurationMillisAtPowerLevel( @@ -416,6 +415,7 @@ public final class ModemActivityInfo implements Parcelable { - getReceiveTimeMillis(rat, freq))); } } else { + int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS]; for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) { txTimeMs[lvl] = (int) (other.getTransmitDurationMillisAtPowerLevel(lvl, rat) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 725518d0626b..ade5543e938a 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16788,32 +16788,6 @@ public class TelephonyManager { } /** - * Callback to listen for when the set of packages with carrier privileges for a SIM changes. - * - * @hide - * @deprecated Use {@link CarrierPrivilegesCallback} instead. This API will be removed soon - * prior to API finalization. - */ - @Deprecated - @SystemApi - public interface CarrierPrivilegesListener { - /** - * Called when the set of packages with carrier privileges has changed. - * - * <p>Of note, this callback will <b>not</b> be fired if a carrier triggers a SIM profile - * switch and the same set of packages remains privileged after the switch. - * - * <p>At registration, the callback will receive the current set of privileged packages. - * - * @param privilegedPackageNames The updated set of package names that have carrier - * privileges - * @param privilegedUids The updated set of UIDs that have carrier privileges - */ - void onCarrierPrivilegesChanged( - @NonNull List<String> privilegedPackageNames, @NonNull int[] privilegedUids); - } - - /** * Callbacks to listen for when the set of packages with carrier privileges for a SIM changes. * * <p>Of note, when multiple callbacks are registered, they may be triggered one after another. @@ -16862,61 +16836,6 @@ public class TelephonyManager { } /** - * Registers a {@link CarrierPrivilegesListener} on the given {@code logicalSlotIndex} to - * receive callbacks when the set of packages with carrier privileges changes. The callback will - * immediately be called with the latest state. - * - * @param logicalSlotIndex The SIM slot to listen on - * @param executor The executor where {@code listener} will be invoked - * @param listener The callback to register - * @hide - * @deprecated Use {@link #registerCarrierPrivilegesCallback} instead. This API will be - * removed prior to API finalization. - */ - @Deprecated - @SystemApi - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void addCarrierPrivilegesListener( - int logicalSlotIndex, - @NonNull @CallbackExecutor Executor executor, - @NonNull CarrierPrivilegesListener listener) { - if (mContext == null) { - throw new IllegalStateException("Telephony service is null"); - } else if (executor == null || listener == null) { - throw new IllegalArgumentException( - "CarrierPrivilegesListener and executor must be non-null"); - } - mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); - if (mTelephonyRegistryMgr == null) { - throw new IllegalStateException("Telephony registry service is null"); - } - mTelephonyRegistryMgr.addCarrierPrivilegesListener(logicalSlotIndex, executor, listener); - } - - /** - * Unregisters an existing {@link CarrierPrivilegesListener}. - * - * @hide - * @deprecated Use {@link #unregisterCarrierPrivilegesCallback} instead. This API will be - * removed prior to API finalization. - */ - @Deprecated - @SystemApi - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void removeCarrierPrivilegesListener(@NonNull CarrierPrivilegesListener listener) { - if (mContext == null) { - throw new IllegalStateException("Telephony service is null"); - } else if (listener == null) { - throw new IllegalArgumentException("CarrierPrivilegesListener must be non-null"); - } - mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class); - if (mTelephonyRegistryMgr == null) { - throw new IllegalStateException("Telephony registry service is null"); - } - mTelephonyRegistryMgr.removeCarrierPrivilegesListener(listener); - } - - /** * Sets a voice service state override from telecom based on the current {@link PhoneAccount}s * registered. See {@link PhoneAccount#CAPABILITY_VOICE_CALLING_AVAILABLE}. * |