diff options
871 files changed, 24097 insertions, 12155 deletions
diff --git a/Android.bp b/Android.bp index 4a1f96ece71d..5e068ee393cd 100644 --- a/Android.bp +++ b/Android.bp @@ -481,6 +481,7 @@ java_library { "framework-platform-compat-config", "libcore-platform-compat-config", "services-platform-compat-config", + "documents-ui-compat-config", ], static_libs: [ // If MimeMap ever becomes its own APEX, then this dependency would need to be removed diff --git a/apex/Android.bp b/apex/Android.bp index 362cf95b3832..051986e758d3 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -31,12 +31,12 @@ mainline_stubs_args += "--hide-package com.android.server " priv_apps = " " + "--show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," + + "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" + "\\) " module_libs = " " + " --show-annotation android.annotation.SystemApi\\(" + - "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," + + "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" + "\\) " stubs_defaults { @@ -48,6 +48,7 @@ stubs_defaults { stubs_defaults { name: "framework-module-stubs-defaults-systemapi", args: mainline_stubs_args + priv_apps, + srcs: [":framework-annotations"], installable: false, } @@ -59,11 +60,13 @@ stubs_defaults { stubs_defaults { name: "framework-module-api-defaults-module_libs_api", args: mainline_stubs_args + module_libs, + srcs: [":framework-annotations"], installable: false, } stubs_defaults { name: "framework-module-stubs-defaults-module_libs_api", args: mainline_stubs_args + module_libs + priv_apps, + srcs: [":framework-annotations"], installable: false, } diff --git a/apex/extservices/Android.bp b/apex/extservices/Android.bp index c89f694c09d2..021246cc7404 100644 --- a/apex/extservices/Android.bp +++ b/apex/extservices/Android.bp @@ -20,6 +20,7 @@ apex { apex_defaults { name: "com.android.extservices-defaults", + updatable: true, key: "com.android.extservices.key", certificate: ":com.android.extservices.certificate", apps: ["ExtServices"], diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java index 4c98b5fd3b56..62c90dfa8a86 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java @@ -54,7 +54,8 @@ public class JobParameters implements Parcelable { * * @hide */ - public static final int REASON_RESTRAINED = JobProtoEnums.STOP_REASON_RESTRAINED; // 6. + public static final int REASON_RESTRICTED_BUCKET = + JobProtoEnums.STOP_REASON_RESTRICTED_BUCKET; // 6. /** * All the stop reason codes. This should be regarded as an immutable array at runtime. @@ -72,7 +73,7 @@ public class JobParameters implements Parcelable { REASON_TIMEOUT, REASON_DEVICE_IDLE, REASON_DEVICE_THERMAL, - REASON_RESTRAINED, + REASON_RESTRICTED_BUCKET, }; /** @@ -88,7 +89,7 @@ public class JobParameters implements Parcelable { case REASON_TIMEOUT: return "timeout"; case REASON_DEVICE_IDLE: return "device_idle"; case REASON_DEVICE_THERMAL: return "thermal"; - case REASON_RESTRAINED: return "restrained"; + case REASON_RESTRICTED_BUCKET: return "restricted_bucket"; default: return "unknown:" + reasonCode; } } 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 c1e529f3f966..8c08e757e405 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1074,7 +1074,15 @@ public class JobSchedulerService extends com.android.server.SystemService uId, null, jobStatus.getBatteryName(), FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED, JobProtoEnums.STOP_REASON_CANCELLED, jobStatus.getStandbyBucket(), - jobStatus.getJobId()); + jobStatus.getJobId(), + jobStatus.hasChargingConstraint(), + jobStatus.hasBatteryNotLowConstraint(), + jobStatus.hasStorageNotLowConstraint(), + jobStatus.hasTimingDelayConstraint(), + jobStatus.hasDeadlineConstraint(), + jobStatus.hasIdleConstraint(), + jobStatus.hasConnectivityConstraint(), + jobStatus.hasContentTriggerConstraint()); // If the job is immediately ready to run, then we can just immediately // put it in the pending list and try to schedule it. This is especially @@ -1955,9 +1963,19 @@ public class JobSchedulerService extends com.android.server.SystemService continue; } if (!running.isReady()) { - serviceContext.cancelExecutingJobLocked( - JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED, - "cancelled due to unsatisfied constraints"); + // If a restricted job doesn't have dynamic constraints satisfied, assume that's + // the reason the job is being stopped, instead of because of other constraints + // not being satisfied. + if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX + && !running.areDynamicConstraintsSatisfied()) { + serviceContext.cancelExecutingJobLocked( + JobParameters.REASON_RESTRICTED_BUCKET, + "cancelled due to restricted bucket"); + } else { + serviceContext.cancelExecutingJobLocked( + JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED, + "cancelled due to unsatisfied constraints"); + } } else { final JobRestriction restriction = checkIfRestricted(running); if (restriction != null) { @@ -3015,6 +3033,10 @@ public class JobSchedulerService extends com.android.server.SystemService return 0; } + void resetExecutionQuota(@NonNull String pkgName, int userId) { + mQuotaController.clearAppStats(userId, pkgName); + } + void resetScheduleQuota() { mQuotaTracker.clear(); } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index 6becf04deb98..957170890a8f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -66,6 +66,8 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { return getJobState(pw); case "heartbeat": return doHeartbeat(pw); + case "reset-execution-quota": + return resetExecutionQuota(pw); case "reset-schedule-quota": return resetScheduleQuota(pw); case "trigger-dock-state": @@ -346,6 +348,40 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { return -1; } + private int resetExecutionQuota(PrintWriter pw) throws Exception { + checkPermission("reset execution quota"); + + int userId = UserHandle.USER_SYSTEM; + + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "-u": + case "--user": + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + + default: + pw.println("Error: unknown option '" + opt + "'"); + return -1; + } + } + + if (userId == UserHandle.USER_CURRENT) { + userId = ActivityManager.getCurrentUser(); + } + + final String pkgName = getNextArgRequired(); + + final long ident = Binder.clearCallingIdentity(); + try { + mInternal.resetExecutionQuota(pkgName, userId); + } finally { + Binder.restoreCallingIdentity(ident); + } + return 0; + } + private int resetScheduleQuota(PrintWriter pw) throws Exception { checkPermission("reset schedule quota"); 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 26db4a30ebda..565ed959aeb4 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -22,6 +22,7 @@ import android.app.job.IJobCallback; import android.app.job.IJobService; import android.app.job.JobInfo; import android.app.job.JobParameters; +import android.app.job.JobProtoEnums; import android.app.job.JobWorkItem; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; @@ -45,6 +46,7 @@ import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.job.controllers.JobStatus; @@ -273,9 +275,20 @@ public final class JobServiceContext implements ServiceConnection { return false; } mJobPackageTracker.noteActive(job); + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, + job.getSourceUid(), null, job.getBatteryName(), + FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED, + JobProtoEnums.STOP_REASON_UNKNOWN, job.getStandbyBucket(), job.getJobId(), + job.hasChargingConstraint(), + job.hasBatteryNotLowConstraint(), + job.hasStorageNotLowConstraint(), + job.hasTimingDelayConstraint(), + job.hasDeadlineConstraint(), + job.hasIdleConstraint(), + job.hasConnectivityConstraint(), + job.hasContentTriggerConstraint()); try { - mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid(), - job.getStandbyBucket(), job.getJobId()); + mBatteryStats.noteJobStart(job.getBatteryName(), job.getSourceUid()); } catch (RemoteException e) { // Whatever. } @@ -779,10 +792,21 @@ public final class JobServiceContext implements ServiceConnection { applyStoppedReasonLocked(reason); completedJob = mRunningJob; mJobPackageTracker.noteInactive(completedJob, mParams.getStopReason(), reason); + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, + completedJob.getSourceUid(), null, completedJob.getBatteryName(), + FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED, + mParams.getStopReason(), completedJob.getStandbyBucket(), completedJob.getJobId(), + completedJob.hasChargingConstraint(), + completedJob.hasBatteryNotLowConstraint(), + completedJob.hasStorageNotLowConstraint(), + completedJob.hasTimingDelayConstraint(), + completedJob.hasDeadlineConstraint(), + completedJob.hasIdleConstraint(), + completedJob.hasConnectivityConstraint(), + completedJob.hasContentTriggerConstraint()); try { - mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), - mRunningJob.getSourceUid(), mParams.getStopReason(), - mRunningJob.getStandbyBucket(), mRunningJob.getJobId()); + mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(), mRunningJob.getSourceUid(), + mParams.getStopReason()); } catch (RemoteException e) { // Whatever. } diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING new file mode 100644 index 000000000000..9a7d55aa06ba --- /dev/null +++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING @@ -0,0 +1,19 @@ +{ + "postsubmit": [ + { + "name": "CtsJobSchedulerTestCases" + }, + { + "name": "FrameworksMockingServicesTests", + "options": [ + {"include-filter": "com.android.server.job"} + ] + }, + { + "name": "FrameworksServicesTests", + "options": [ + {"include-filter": "com.android.server.job"} + ] + } + ] +} diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java index aa3d74a51ff2..d7b1e0793f67 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -16,6 +16,8 @@ package com.android.server.job.controllers; +import static com.android.server.job.JobSchedulerService.NEVER_INDEX; + import android.os.SystemClock; import android.os.UserHandle; import android.util.Log; @@ -196,6 +198,9 @@ public final class BackgroundJobsController extends StateController { } else { isActive = (activeState == KNOWN_ACTIVE); } + if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) { + Slog.wtf(TAG, "App became active but still in NEVER bucket"); + } boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun); didChange |= jobStatus.setUidActive(isActive); return didChange; diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index b63cc1918a7a..81dbc873fa57 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -1271,7 +1271,8 @@ public final class JobStatus { // sessions (exempt from dynamic restrictions), we need the additional check to ensure // that NEVER jobs don't run. // TODO: cleanup quota and standby bucket management so we don't need the additional checks - if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) || standbyBucket == NEVER_INDEX) { + if ((!mReadyWithinQuota && !mReadyDynamicSatisfied) + || getEffectiveStandbyBucket() == NEVER_INDEX) { return false; } // Deadline constraint trumps other constraints besides quota and dynamic (except for @@ -1293,6 +1294,11 @@ public final class JobStatus { CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE; + /** Returns true whenever all dynamically set constraints are satisfied. */ + public boolean areDynamicConstraintsSatisfied() { + return mReadyDynamicSatisfied; + } + /** * @return Whether the constraints set on this job are satisfied. */ diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index 8eefac8abdac..7256371102f5 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -54,12 +54,14 @@ import android.provider.Settings; import android.util.ArraySet; import android.util.KeyValueListParser; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseArrayMap; import android.util.SparseBooleanArray; import android.util.SparseSetArray; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; @@ -74,6 +76,7 @@ import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.PriorityQueue; import java.util.function.Consumer; import java.util.function.Predicate; @@ -301,10 +304,10 @@ public final class QuotaController extends StateController { private final SparseArrayMap<List<TimingSession>> mTimingSessions = new SparseArrayMap<>(); /** - * List of alarm listeners for each package that listen for when each package comes back within - * quota. + * Listener to track and manage when each package comes back within quota. */ - private final SparseArrayMap<QcAlarmListener> mInQuotaAlarmListeners = new SparseArrayMap<>(); + @GuardedBy("mLock") + private final InQuotaAlarmListener mInQuotaAlarmListener = new InQuotaAlarmListener(); /** Cached calculation results for each app, with the standby buckets as the array indices. */ private final SparseArrayMap<ExecutionStats[]> mExecutionStatsCache = new SparseArrayMap<>(); @@ -579,23 +582,7 @@ public final class QuotaController extends StateController { Slog.wtf(TAG, "Told app removed but given null package name."); return; } - final int userId = UserHandle.getUserId(uid); - mTrackedJobs.delete(userId, packageName); - Timer timer = mPkgTimers.get(userId, packageName); - if (timer != null) { - if (timer.isActive()) { - Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off."); - timer.dropEverythingLocked(); - } - mPkgTimers.delete(userId, packageName); - } - mTimingSessions.delete(userId, packageName); - QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName); - if (alarmListener != null) { - mAlarmManager.cancel(alarmListener); - mInQuotaAlarmListeners.delete(userId, packageName); - } - mExecutionStatsCache.delete(userId, packageName); + clearAppStats(UserHandle.getUserId(uid), packageName); mForegroundUids.delete(uid); mUidToPackageCache.remove(uid); } @@ -605,11 +592,27 @@ public final class QuotaController extends StateController { mTrackedJobs.delete(userId); mPkgTimers.delete(userId); mTimingSessions.delete(userId); - mInQuotaAlarmListeners.delete(userId); + mInQuotaAlarmListener.removeAlarmsLocked(userId); mExecutionStatsCache.delete(userId); mUidToPackageCache.clear(); } + /** Drop all historical stats and stop tracking any active sessions for the specified app. */ + public void clearAppStats(int userId, @NonNull String packageName) { + mTrackedJobs.delete(userId, packageName); + Timer timer = mPkgTimers.get(userId, packageName); + if (timer != null) { + if (timer.isActive()) { + Slog.e(TAG, "clearAppStats called before Timer turned off."); + timer.dropEverythingLocked(); + } + mPkgTimers.delete(userId, packageName); + } + mTimingSessions.delete(userId, packageName); + mInQuotaAlarmListener.removeAlarmLocked(userId, packageName); + mExecutionStatsCache.delete(userId, packageName); + } + private boolean isUidInForeground(int uid) { if (UserHandle.isCore(uid)) { return true; @@ -1204,12 +1207,7 @@ public final class QuotaController extends StateController { // exempted. maybeScheduleStartAlarmLocked(userId, packageName, realStandbyBucket); } else { - QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName); - if (alarmListener != null && alarmListener.isWaiting()) { - mAlarmManager.cancel(alarmListener); - // Set the trigger time to 0 so that the alarm doesn't think it's still waiting. - alarmListener.setTriggerTime(0); - } + mInQuotaAlarmListener.removeAlarmLocked(userId, packageName); } return changed; } @@ -1225,12 +1223,7 @@ public final class QuotaController extends StateController { final String packageName = jobStatus.getSourcePackageName(); final int realStandbyBucket = jobStatus.getStandbyBucket(); if (isWithinQuotaLocked(userId, packageName, realStandbyBucket)) { - QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName); - if (alarmListener != null && alarmListener.isWaiting()) { - mAlarmManager.cancel(alarmListener); - // Set the trigger time to 0 so that the alarm doesn't think it's still waiting. - alarmListener.setTriggerTime(0); - } + mInQuotaAlarmListener.removeAlarmLocked(userId, packageName); } else { mToScheduleStartAlarms.add(userId, packageName, realStandbyBucket); } @@ -1281,7 +1274,6 @@ public final class QuotaController extends StateController { final boolean isUnderTimingSessionCountQuota = isUnderSessionCountQuotaLocked(stats, standbyBucket); - QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName); if (stats.executionTimeInWindowMs < mAllowedTimePerPeriodMs && stats.executionTimeInMaxPeriodMs < mMaxExecutionTimeMs && isUnderJobCountQuota @@ -1293,21 +1285,11 @@ public final class QuotaController extends StateController { + getRemainingExecutionTimeLocked(userId, packageName, standbyBucket) + "ms in its quota."); } - if (alarmListener != null) { - // Cancel any pending alarm. - mAlarmManager.cancel(alarmListener); - // Set the trigger time to 0 so that the alarm doesn't think it's still waiting. - alarmListener.setTriggerTime(0); - } + mInQuotaAlarmListener.removeAlarmLocked(userId, packageName); mHandler.obtainMessage(MSG_CHECK_PACKAGE, userId, 0, packageName).sendToTarget(); return; } - if (alarmListener == null) { - alarmListener = new QcAlarmListener(userId, packageName); - mInQuotaAlarmListeners.add(userId, packageName, alarmListener); - } - // The time this app will have quota again. long inQuotaTimeElapsed = stats.inQuotaTimeElapsed; if (!isUnderJobCountQuota && stats.bgJobCountInWindow < stats.jobCountLimit) { @@ -1321,27 +1303,7 @@ public final class QuotaController extends StateController { inQuotaTimeElapsed = Math.max(inQuotaTimeElapsed, stats.sessionRateLimitExpirationTimeElapsed); } - // Only schedule the alarm if: - // 1. There isn't one currently scheduled - // 2. The new alarm is significantly earlier than the previous alarm (which could be the - // case if the package moves into a higher standby bucket). If it's earlier but not - // significantly so, then we essentially delay the job a few extra minutes. - // 3. The alarm is after the current alarm by more than the quota buffer. - // TODO: this might be overengineering. Simplify if proven safe. - if (!alarmListener.isWaiting() - || inQuotaTimeElapsed < alarmListener.getTriggerTimeElapsed() - 3 * MINUTE_IN_MILLIS - || alarmListener.getTriggerTimeElapsed() < inQuotaTimeElapsed) { - if (DEBUG) { - Slog.d(TAG, "Scheduling start alarm for " + pkgString); - } - // If the next time this app will have quota is at least 3 minutes before the - // alarm is supposed to go off, reschedule the alarm. - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, inQuotaTimeElapsed, - ALARM_TAG_QUOTA_CHECK, alarmListener, mHandler); - alarmListener.setTriggerTime(inQuotaTimeElapsed); - } else if (DEBUG) { - Slog.d(TAG, "No need to schedule start alarm for " + pkgString); - } + mInQuotaAlarmListener.addAlarmLocked(userId, packageName, inQuotaTimeElapsed); } private boolean setConstraintSatisfied(@NonNull JobStatus jobStatus, boolean isWithinQuota) { @@ -1871,32 +1833,161 @@ public final class QuotaController extends StateController { } } - private class QcAlarmListener implements AlarmManager.OnAlarmListener { - private final int mUserId; - private final String mPackageName; - private volatile long mTriggerTimeElapsed; + static class AlarmQueue extends PriorityQueue<Pair<Package, Long>> { + AlarmQueue() { + super(1, (o1, o2) -> (int) (o1.second - o2.second)); + } - QcAlarmListener(int userId, String packageName) { - mUserId = userId; - mPackageName = packageName; + /** + * Remove any instances of the Package from the queue. + * + * @return true if an instance was removed, false otherwise. + */ + boolean remove(@NonNull Package pkg) { + boolean removed = false; + Pair[] alarms = toArray(new Pair[size()]); + for (int i = alarms.length - 1; i >= 0; --i) { + if (pkg.equals(alarms[i].first)) { + remove(alarms[i]); + removed = true; + } + } + return removed; } + } + + /** Track when UPTCs are expected to come back into quota. */ + private class InQuotaAlarmListener implements AlarmManager.OnAlarmListener { + @GuardedBy("mLock") + private final AlarmQueue mAlarmQueue = new AlarmQueue(); + /** The next time the alarm is set to go off, in the elapsed realtime timebase. */ + @GuardedBy("mLock") + private long mTriggerTimeElapsed = 0; - boolean isWaiting() { - return mTriggerTimeElapsed > 0; + @GuardedBy("mLock") + void addAlarmLocked(int userId, @NonNull String pkgName, long inQuotaTimeElapsed) { + final Package pkg = new Package(userId, pkgName); + mAlarmQueue.remove(pkg); + mAlarmQueue.offer(new Pair<>(pkg, inQuotaTimeElapsed)); + setNextAlarmLocked(); } - void setTriggerTime(long timeElapsed) { - mTriggerTimeElapsed = timeElapsed; + @GuardedBy("mLock") + void removeAlarmLocked(@NonNull Package pkg) { + if (mAlarmQueue.remove(pkg)) { + setNextAlarmLocked(); + } } - long getTriggerTimeElapsed() { - return mTriggerTimeElapsed; + @GuardedBy("mLock") + void removeAlarmLocked(int userId, @NonNull String packageName) { + removeAlarmLocked(new Package(userId, packageName)); + } + + @GuardedBy("mLock") + void removeAlarmsLocked(int userId) { + boolean removed = false; + Pair[] alarms = mAlarmQueue.toArray(new Pair[mAlarmQueue.size()]); + for (int i = alarms.length - 1; i >= 0; --i) { + final Package pkg = (Package) alarms[i].first; + if (userId == pkg.userId) { + mAlarmQueue.remove(alarms[i]); + removed = true; + } + } + if (removed) { + setNextAlarmLocked(); + } + } + + @GuardedBy("mLock") + private void setNextAlarmLocked() { + if (mAlarmQueue.size() > 0) { + final long nextTriggerTimeElapsed = mAlarmQueue.peek().second; + // Only schedule the alarm if one of the following is true: + // 1. There isn't one currently scheduled + // 2. The new alarm is significantly earlier than the previous alarm. If it's + // earlier but not significantly so, then we essentially delay the job a few extra + // minutes. + // 3. The alarm is after the current alarm. + if (mTriggerTimeElapsed == 0 + || nextTriggerTimeElapsed < mTriggerTimeElapsed - 3 * MINUTE_IN_MILLIS + || mTriggerTimeElapsed < nextTriggerTimeElapsed) { + if (DEBUG) { + Slog.d(TAG, "Scheduling start alarm at " + nextTriggerTimeElapsed); + } + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextTriggerTimeElapsed, + ALARM_TAG_QUOTA_CHECK, this, mHandler); + mTriggerTimeElapsed = nextTriggerTimeElapsed; + } + } else { + mAlarmManager.cancel(this); + mTriggerTimeElapsed = 0; + } } @Override public void onAlarm() { - mHandler.obtainMessage(MSG_CHECK_PACKAGE, mUserId, 0, mPackageName).sendToTarget(); - mTriggerTimeElapsed = 0; + synchronized (mLock) { + while (mAlarmQueue.size() > 0) { + final Pair<Package, Long> alarm = mAlarmQueue.peek(); + if (alarm.second <= sElapsedRealtimeClock.millis()) { + mHandler.obtainMessage(MSG_CHECK_PACKAGE, alarm.first.userId, 0, + alarm.first.packageName).sendToTarget(); + mAlarmQueue.remove(alarm); + } else { + break; + } + } + setNextAlarmLocked(); + } + } + + @GuardedBy("mLock") + void dumpLocked(IndentingPrintWriter pw) { + pw.println("In quota alarms:"); + pw.increaseIndent(); + + if (mAlarmQueue.size() == 0) { + pw.println("NOT WAITING"); + } else { + Pair[] alarms = mAlarmQueue.toArray(new Pair[mAlarmQueue.size()]); + for (int i = 0; i < alarms.length; ++i) { + final Package pkg = (Package) alarms[i].first; + pw.print(pkg); + pw.print(": "); + pw.print(alarms[i].second); + pw.println(); + } + } + + pw.decreaseIndent(); + } + + @GuardedBy("mLock") + void dumpLocked(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + + proto.write( + StateControllerProto.QuotaController.InQuotaAlarmListener.TRIGGER_TIME_ELAPSED, + mTriggerTimeElapsed); + + Pair[] alarms = mAlarmQueue.toArray(new Pair[mAlarmQueue.size()]); + for (int i = 0; i < alarms.length; ++i) { + final long aToken = proto.start( + StateControllerProto.QuotaController.InQuotaAlarmListener.ALARMS); + + final Package pkg = (Package) alarms[i].first; + pkg.dumpDebug(proto, + StateControllerProto.QuotaController.InQuotaAlarmListener.Alarm.PKG); + proto.write( + StateControllerProto.QuotaController.InQuotaAlarmListener.Alarm.IN_QUOTA_TIME_ELAPSED, + (Long) alarms[i].second); + + proto.end(aToken); + } + + proto.end(token); } } @@ -2614,23 +2705,7 @@ public final class QuotaController extends StateController { pw.decreaseIndent(); pw.println(); - pw.println("In quota alarms:"); - pw.increaseIndent(); - for (int u = 0; u < mInQuotaAlarmListeners.numMaps(); ++u) { - final int userId = mInQuotaAlarmListeners.keyAt(u); - for (int p = 0; p < mInQuotaAlarmListeners.numElementsForKey(userId); ++p) { - final String pkgName = mInQuotaAlarmListeners.keyAt(u, p); - QcAlarmListener alarmListener = mInQuotaAlarmListeners.valueAt(u, p); - - pw.print(string(userId, pkgName)); - pw.print(": "); - if (alarmListener.isWaiting()) { - pw.println(alarmListener.getTriggerTimeElapsed()); - } else { - pw.println("NOT WAITING"); - } - } - } + mInQuotaAlarmListener.dumpLocked(pw); pw.decreaseIndent(); } @@ -2764,22 +2839,13 @@ public final class QuotaController extends StateController { } } - QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, pkgName); - if (alarmListener != null) { - final long alToken = proto.start( - StateControllerProto.QuotaController.PackageStats.IN_QUOTA_ALARM_LISTENER); - proto.write(StateControllerProto.QuotaController.AlarmListener.IS_WAITING, - alarmListener.isWaiting()); - proto.write( - StateControllerProto.QuotaController.AlarmListener.TRIGGER_TIME_ELAPSED, - alarmListener.getTriggerTimeElapsed()); - proto.end(alToken); - } - proto.end(psToken); } } + mInQuotaAlarmListener.dumpLocked(proto, + StateControllerProto.QuotaController.IN_QUOTA_ALARM_LISTENER); + proto.end(mToken); proto.end(token); } 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 932c25d7bd0e..46d449a9257c 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java @@ -21,6 +21,7 @@ import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER; import static android.app.usage.UsageStatsManager.REASON_MAIN_MASK; import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED; import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE; +import static android.app.usage.UsageStatsManager.REASON_SUB_MASK; import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE; import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER; @@ -43,6 +44,7 @@ import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import libcore.io.IoUtils; @@ -244,9 +246,9 @@ public class AppIdleHistory { * @param elapsedRealtime mark as used time if non-zero * @param timeout set the timeout of the specified bucket, if non-zero. Can only be used * with bucket values of ACTIVE and WORKING_SET. - * @return + * @return {@code appUsageHistory} */ - public AppUsageHistory reportUsage(AppUsageHistory appUsageHistory, String packageName, + AppUsageHistory reportUsage(AppUsageHistory appUsageHistory, String packageName, int userId, int newBucket, int usageReason, long elapsedRealtime, long timeout) { int bucketingReason = REASON_MAIN_USAGE | usageReason; final boolean isUserUsage = isUserUsage(bucketingReason); @@ -284,11 +286,7 @@ public class AppIdleHistory { if (appUsageHistory.currentBucket > newBucket) { appUsageHistory.currentBucket = newBucket; - if (DEBUG) { - Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory - .currentBucket - + ", reason=0x0" + Integer.toHexString(appUsageHistory.bucketingReason)); - } + logAppStandbyBucketChanged(packageName, userId, newBucket, bucketingReason); } appUsageHistory.bucketingReason = bucketingReason; @@ -313,7 +311,8 @@ public class AppIdleHistory { int usageReason, long nowElapsed, long timeout) { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory history = getPackageHistory(userHistory, packageName, nowElapsed, true); - return reportUsage(history, packageName, newBucket, usageReason, nowElapsed, timeout); + return reportUsage(history, packageName, userId, newBucket, usageReason, nowElapsed, + timeout); } private ArrayMap<String, AppUsageHistory> getUserHistory(int userId) { @@ -372,6 +371,7 @@ public class AppIdleHistory { ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, elapsedRealtime, true); + final boolean changed = appUsageHistory.currentBucket != bucket; appUsageHistory.currentBucket = bucket; appUsageHistory.bucketingReason = reason; @@ -385,9 +385,8 @@ public class AppIdleHistory { appUsageHistory.bucketActiveTimeoutTime = elapsed; appUsageHistory.bucketWorkingSetTimeoutTime = elapsed; } - if (DEBUG) { - Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket - + ", reason=0x0" + Integer.toHexString(appUsageHistory.bucketingReason)); + if (changed) { + logAppStandbyBucketChanged(packageName, userId, bucket, reason); } } @@ -485,18 +484,19 @@ public class AppIdleHistory { /* Returns the new standby bucket the app is assigned to */ public int setIdle(String packageName, int userId, boolean idle, long elapsedRealtime) { - ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId); - AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName, - elapsedRealtime, true); + final int newBucket; + final int reason; if (idle) { - appUsageHistory.currentBucket = STANDBY_BUCKET_RARE; - appUsageHistory.bucketingReason = REASON_MAIN_FORCED_BY_USER; + newBucket = STANDBY_BUCKET_RARE; + reason = REASON_MAIN_FORCED_BY_USER; } else { - appUsageHistory.currentBucket = STANDBY_BUCKET_ACTIVE; + newBucket = STANDBY_BUCKET_ACTIVE; // This is to pretend that the app was just used, don't freeze the state anymore. - appUsageHistory.bucketingReason = REASON_MAIN_USAGE | REASON_SUB_USAGE_USER_INTERACTION; + reason = REASON_MAIN_USAGE | REASON_SUB_USAGE_USER_INTERACTION; } - return appUsageHistory.currentBucket; + setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason, false); + + return newBucket; } public void clearUsage(String packageName, int userId) { @@ -551,13 +551,27 @@ public class AppIdleHistory { return 0; } + /** + * Log a standby bucket change to statsd, and also logcat if debug logging is enabled. + */ + private void logAppStandbyBucketChanged(String packageName, int userId, int bucket, + int reason) { + FrameworkStatsLog.write( + FrameworkStatsLog.APP_STANDBY_BUCKET_CHANGED, + packageName, userId, bucket, + (reason & REASON_MAIN_MASK), (reason & REASON_SUB_MASK)); + if (DEBUG) { + Slog.d(TAG, "Moved " + packageName + " to bucket=" + bucket + + ", reason=0x0" + Integer.toHexString(reason)); + } + } + @VisibleForTesting File getUserFile(int userId) { return new File(new File(new File(mStorageDir, "users"), Integer.toString(userId)), APP_IDLE_FILENAME); } - /** * 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 7a1b4f275ab0..5992253efda3 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -831,24 +831,24 @@ public class AppStandbyController implements AppStandbyInternal { if (eventType == UsageEvents.Event.NOTIFICATION_SEEN || eventType == UsageEvents.Event.SLICE_PINNED) { // Mild usage elevates to WORKING_SET but doesn't change usage time. - mAppIdleHistory.reportUsage(appHistory, pkg, + mAppIdleHistory.reportUsage(appHistory, pkg, userId, STANDBY_BUCKET_WORKING_SET, subReason, 0, elapsedRealtime + mNotificationSeenTimeoutMillis); nextCheckDelay = mNotificationSeenTimeoutMillis; } else if (eventType == UsageEvents.Event.SYSTEM_INTERACTION) { - mAppIdleHistory.reportUsage(appHistory, pkg, + mAppIdleHistory.reportUsage(appHistory, pkg, userId, STANDBY_BUCKET_ACTIVE, subReason, 0, elapsedRealtime + mSystemInteractionTimeoutMillis); nextCheckDelay = mSystemInteractionTimeoutMillis; } else if (eventType == UsageEvents.Event.FOREGROUND_SERVICE_START) { // Only elevate bucket if this is the first usage of the app if (prevBucket != STANDBY_BUCKET_NEVER) return; - mAppIdleHistory.reportUsage(appHistory, pkg, + mAppIdleHistory.reportUsage(appHistory, pkg, userId, STANDBY_BUCKET_ACTIVE, subReason, 0, elapsedRealtime + mInitialForegroundServiceStartTimeoutMillis); nextCheckDelay = mInitialForegroundServiceStartTimeoutMillis; } else { - mAppIdleHistory.reportUsage(appHistory, pkg, + mAppIdleHistory.reportUsage(appHistory, pkg, userId, STANDBY_BUCKET_ACTIVE, subReason, elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis); nextCheckDelay = mStrongUsageTimeoutMillis; diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING index cf70878b8899..ba7572a5fb44 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING +++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING @@ -1,6 +1,13 @@ { "presubmit": [ { + "name": "CtsUsageStatsTestCases", + "options": [ + {"include-filter": "android.app.usage.cts.UsageStatsTest"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"} + ] + }, + { "name": "FrameworksServicesTests", "options": [ {"include-filter": "com.android.server.usage"}, @@ -10,6 +17,9 @@ ], "postsubmit": [ { + "name": "CtsUsageStatsTestCases" + }, + { "name": "FrameworksServicesTests", "options": [ {"include-filter": "com.android.server.usage"} diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index 11d3a6867ac3..a4f7b5bf5e24 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -94,61 +94,84 @@ import java.util.Map; * which extracts and publishes all video samples: * * <pre> - * * class VideoOutputConsumer implements MediaParser.OutputConsumer { * - * private static final int MAXIMUM_SAMPLE_SIZE = ...; - * private byte[] sampleDataBuffer = new byte[MAXIMUM_SAMPLE_SIZE]; + * private byte[] sampleDataBuffer = new byte[4096]; + * private byte[] discardedDataBuffer = new byte[4096]; * private int videoTrackIndex = -1; * private int bytesWrittenCount = 0; * - * \@Override - * public void onSeekMap(int i, @NonNull MediaFormat mediaFormat) { \/* Do nothing. *\/ } + * @Override + * public void onSeekMap(int i, @NonNull MediaFormat mediaFormat) { + * // Do nothing. + * } * - * \@Override - * public void onTrackData(int i, @NonNull TrackData trackData) { + * @Override + * public void onTrackData(int i, @NonNull TrackData trackData) { * MediaFormat mediaFormat = trackData.mediaFormat; - * if (videoTrackIndex == -1 && mediaFormat - * .getString(MediaFormat.KEY_MIME, \/* defaultValue= *\/ "").startsWith("video/")) { + * if (videoTrackIndex == -1 && + * mediaFormat + * .getString(MediaFormat.KEY_MIME, /* defaultValue= */ "") + * .startsWith("video/")) { * videoTrackIndex = i; * } * } * - * \@Override - * public void onSampleData(int trackIndex, @NonNull InputReader inputReader) + * @Override + * public void onSampleData(int trackIndex, @NonNull InputReader inputReader) * throws IOException, InterruptedException { * int numberOfBytesToRead = (int) inputReader.getLength(); * if (videoTrackIndex != trackIndex) { * // Discard contents. - * inputReader.read(\/* bytes= *\/ null, \/* offset= *\/ 0, numberOfBytesToRead); + * inputReader.read( + * discardedDataBuffer, + * /* offset= */ 0, + * Math.min(discardDataBuffer.length, numberOfBytesToRead)); + * } else { + * ensureSpaceInBuffer(numberOfBytesToRead); + * int bytesRead = inputReader.read( + * sampleDataBuffer, bytesWrittenCount, numberOfBytesToRead); + * bytesWrittenCount += bytesRead; * } - * int bytesRead = inputReader.read(sampleDataBuffer, bytesWrittenCount, numberOfBytesToRead); - * bytesWrittenCount += bytesRead; * } * - * \@Override + * @Override * public void onSampleCompleted( * int trackIndex, * long timeUs, * int flags, * int size, * int offset, - * \@Nullable CryptoInfo cryptoData) { + * @Nullable CryptoInfo cryptoData) { * if (videoTrackIndex != trackIndex) { * return; // It's not the video track. Ignore. * } * byte[] sampleData = new byte[size]; - * System.arraycopy(sampleDataBuffer, bytesWrittenCount - size - offset, sampleData, \/* - * destPos= *\/ 0, size); + * int sampleStartOffset = bytesWrittenCount - size - offset; + * System.arraycopy( + * sampleDataBuffer, + * sampleStartOffset, + * sampleData, + * /* destPos= */ 0, + * size); * // Place trailing bytes at the start of the buffer. * System.arraycopy( * sampleDataBuffer, * bytesWrittenCount - offset, * sampleDataBuffer, - * \/* destPos= *\/ 0, - * \/* size= *\/ offset); + * /* destPos= */ 0, + * /* size= */ offset); + * bytesWrittenCount = bytesWrittenCount - offset; * publishSample(sampleData, timeUs, flags); * } + * + * private void ensureSpaceInBuffer(int numberOfBytesToRead) { + * int requiredLength = bytesWrittenCount + numberOfBytesToRead; + * if (requiredLength > sampleDataBuffer.length) { + * sampleDataBuffer = Arrays.copyOf(sampleDataBuffer, requiredLength); + * } + * } + * * } * * </pre> @@ -342,11 +365,16 @@ public final class MediaParser { /** * Called to write sample data to the output. * - * <p>Implementers must attempt to consume the entirety of the input, but should surface any - * thrown {@link IOException} caused by reading from {@code input}. + * <p>If the invocation of this method returns before the entire {@code inputReader} {@link + * InputReader#getLength() length} is consumed, the method will be called again for the + * implementer to read the remaining data. Implementers should surface any thrown {@link + * IOException} caused by reading from {@code input}. * * @param trackIndex The index of the track to which the sample data corresponds. * @param inputReader The {@link InputReader} from which to read the data. + * @throws IOException If an exception occurs while reading from {@code inputReader}. + * @throws InterruptedException If an interruption occurs while reading from {@code + * inputReader}. */ void onSampleData(int trackIndex, @NonNull InputReader inputReader) throws IOException, InterruptedException; @@ -361,8 +389,9 @@ public final class MediaParser { * @param flags Flags associated with the sample. See {@link MediaCodec * MediaCodec.BUFFER_FLAG_*}. * @param size The size of the sample data, in bytes. - * @param offset The number of bytes that have been passed to {@link #onSampleData} since - * the last byte belonging to the sample whose metadata is being passed. + * @param offset The number of bytes that have been consumed by {@code onSampleData(int, + * MediaParser.InputReader)} for the specified track, since the last byte belonging to + * the sample whose metadata is being passed. * @param cryptoData Encryption data required to decrypt the sample. May be null for * unencrypted samples. */ @@ -684,7 +713,9 @@ public final class MediaParser { * container data. * @return Whether there is any data left to extract. Returns false if the end of input has been * reached. - * @throws UnrecognizedInputFormatException + * @throws IOException If an error occurs while reading from the {@link SeekableInputReader}. + * @throws UnrecognizedInputFormatException If the format cannot be recognized by any of the + * underlying parser implementations. */ public boolean advance(@NonNull SeekableInputReader seekableInputReader) throws IOException, InterruptedException { @@ -700,30 +731,34 @@ public final class MediaParser { mDataSource.mInputReader = seekableInputReader; // TODO: Apply parameters when creating extractor instances. - if (mExtractorName != null) { - mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance(); - } else if (mExtractor == null) { - for (String parserName : mParserNamesPool) { - Extractor extractor = EXTRACTOR_FACTORIES_BY_NAME.get(parserName).createInstance(); - try { - if (extractor.sniff(mExtractorInput)) { - mExtractorName = parserName; - mExtractor = extractor; - mExtractor.init(new ExtractorOutputAdapter()); - break; + if (mExtractor == null) { + if (mExtractorName != null) { + mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance(); + mExtractor.init(new ExtractorOutputAdapter()); + } else { + for (String parserName : mParserNamesPool) { + Extractor extractor = + EXTRACTOR_FACTORIES_BY_NAME.get(parserName).createInstance(); + try { + if (extractor.sniff(mExtractorInput)) { + mExtractorName = parserName; + mExtractor = extractor; + mExtractor.init(new ExtractorOutputAdapter()); + break; + } + } catch (EOFException e) { + // Do nothing. + } catch (IOException | InterruptedException e) { + throw new IllegalStateException(e); + } finally { + mExtractorInput.resetPeekPosition(); } - } catch (EOFException e) { - // Do nothing. - } catch (IOException | InterruptedException e) { - throw new IllegalStateException(e); - } finally { - mExtractorInput.resetPeekPosition(); } + if (mExtractor == null) { + throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool); + } + return true; } - if (mExtractor == null) { - throw UnrecognizedInputFormatException.createForExtractors(mParserNamesPool); - } - return true; } if (isPendingSeek()) { @@ -1114,20 +1149,22 @@ public final class MediaParser { static { // Using a LinkedHashMap to keep the insertion order when iterating over the keys. LinkedHashMap<String, ExtractorFactory> extractorFactoriesByName = new LinkedHashMap<>(); - extractorFactoriesByName.put("exo.Ac3Parser", Ac3Extractor::new); - extractorFactoriesByName.put("exo.Ac4Parser", Ac4Extractor::new); - extractorFactoriesByName.put("exo.AdtsParser", AdtsExtractor::new); - extractorFactoriesByName.put("exo.AmrParser", AmrExtractor::new); - extractorFactoriesByName.put("exo.FlacParser", FlacExtractor::new); - extractorFactoriesByName.put("exo.FlvParser", FlvExtractor::new); - extractorFactoriesByName.put("exo.FragmentedMp4Parser", FragmentedMp4Extractor::new); + // Parsers are ordered to match ExoPlayer's DefaultExtractorsFactory extractor ordering, + // which in turn aims to minimize the chances of incorrect extractor selections. extractorFactoriesByName.put("exo.MatroskaParser", MatroskaExtractor::new); - extractorFactoriesByName.put("exo.Mp3Parser", Mp3Extractor::new); + extractorFactoriesByName.put("exo.FragmentedMp4Parser", FragmentedMp4Extractor::new); extractorFactoriesByName.put("exo.Mp4Parser", Mp4Extractor::new); + extractorFactoriesByName.put("exo.Mp3Parser", Mp3Extractor::new); + extractorFactoriesByName.put("exo.AdtsParser", AdtsExtractor::new); + extractorFactoriesByName.put("exo.Ac3Parser", Ac3Extractor::new); + extractorFactoriesByName.put("exo.TsParser", TsExtractor::new); + extractorFactoriesByName.put("exo.FlvParser", FlvExtractor::new); extractorFactoriesByName.put("exo.OggParser", OggExtractor::new); extractorFactoriesByName.put("exo.PsParser", PsExtractor::new); - extractorFactoriesByName.put("exo.TsParser", TsExtractor::new); extractorFactoriesByName.put("exo.WavParser", WavExtractor::new); + extractorFactoriesByName.put("exo.AmrParser", AmrExtractor::new); + extractorFactoriesByName.put("exo.Ac4Parser", Ac4Extractor::new); + extractorFactoriesByName.put("exo.FlacParser", FlacExtractor::new); EXTRACTOR_FACTORIES_BY_NAME = Collections.unmodifiableMap(extractorFactoriesByName); HashMap<String, Class> expectedTypeByParameterName = new HashMap<>(); diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp index d746ea6af397..0171b0d76760 100644 --- a/apex/permission/Android.bp +++ b/apex/permission/Android.bp @@ -20,6 +20,7 @@ apex { apex_defaults { name: "com.android.permission-defaults", + updatable: true, key: "com.android.permission.key", certificate: ":com.android.permission.certificate", java_libs: [ diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java index 205ffc297945..30a8b458cce5 100644 --- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java +++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java @@ -246,7 +246,7 @@ public class RuntimePermissionsPersistenceImpl implements RuntimePermissionsPers permissionState.isGranted() && (permissionState.getFlags() & PackageManager.FLAG_PERMISSION_ONE_TIME) == 0)); serializer.attribute(null, ATTRIBUTE_FLAGS, Integer.toHexString( - permissionState.getFlags() & ~PackageManager.FLAG_PERMISSION_ONE_TIME)); + permissionState.getFlags())); serializer.endTag(null, TAG_PERMISSION); } } diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp index 25765afb3ab9..322d5e114541 100644 --- a/apex/sdkextensions/Android.bp +++ b/apex/sdkextensions/Android.bp @@ -26,6 +26,7 @@ apex { apex_defaults { name: "com.android.sdkext-defaults", + updatable: true, java_libs: [ "framework-sdkextensions" ], prebuilts: [ "derive_sdk.rc", diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp index 2f3e2acb5d7a..2df3eea1494d 100644 --- a/apex/statsd/Android.bp +++ b/apex/statsd/Android.bp @@ -32,6 +32,7 @@ apex_defaults { compile_multilib: "both", prebuilts: ["com.android.os.statsd.init.rc"], name: "com.android.os.statsd-defaults", + updatable: true, key: "com.android.os.statsd.key", certificate: ":com.android.os.statsd.certificate", } @@ -63,11 +64,7 @@ cc_library_shared { shared_libs: [ "libnativehelper", // Has stable abi - should not be copied into apex. "liblog", // Has a stable abi - should not be copied into apex. - ], - static_libs: [ - //TODO: make shared - need libstatssocket to also live in the apex. "libstatssocket", - "libcutils", // TODO: remove - needed by libstatssocket ], //TODO: is libc++_static correct? stl: "libc++_static", diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp index 487c8e1b216d..404c63232da9 100644 --- a/apex/statsd/aidl/Android.bp +++ b/apex/statsd/aidl/Android.bp @@ -31,7 +31,7 @@ aidl_interface { ], backend: { java: { - enabled: false, // the platform uses statsd_java_aidl + enabled: false, // framework-statsd and service-statsd use framework-statsd-aidl-sources }, cpp: { enabled: false, diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp index 0f52f15fa86b..1bd770a1ab99 100644 --- a/apex/statsd/framework/Android.bp +++ b/apex/statsd/framework/Android.bp @@ -69,6 +69,8 @@ java_library { "android.util", ], + plugins: ["java_api_finder"], + hostdex: true, // for hiddenapi check visibility: [ "//frameworks/base/apex/statsd:__subpackages__", diff --git a/apex/statsd/service/Android.bp b/apex/statsd/service/Android.bp index 0f325e399d0f..ff56bb513a1d 100644 --- a/apex/statsd/service/Android.bp +++ b/apex/statsd/service/Android.bp @@ -31,6 +31,8 @@ java_library { "android_module_lib_stubs_current", ], + plugins: ["java_api_finder"], + apex_available: [ "com.android.os.statsd", "test_com.android.os.statsd", diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index cb167c30e30f..dc61f2aedf99 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -21,11 +21,13 @@ import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; import android.app.StatsManager; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -85,12 +87,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { public static final int DEATH_THRESHOLD = 10; - // TODO(b/149090705): Implement an alternative to sending broadcast with @hide flag - // FLAG_RECEIVER_INCLUDE_BACKGROUND. Instead of using the flag, find the - // list of registered broadcast receivers and send them directed broadcasts - // to wake them up. See b/147374337. - private static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000; - static final class CompanionHandler extends Handler { CompanionHandler(Looper looper) { super(looper); @@ -498,9 +494,25 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { Log.d(TAG, "learned that statsdReady"); } sayHiToStatsd(); // tell statsd that we're ready too and link to it - mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED) - .addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND), - UserHandle.SYSTEM, android.Manifest.permission.DUMP); + + final Intent intent = new Intent(StatsManager.ACTION_STATSD_STARTED); + // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts + // to wake them up (if they're in background). + List<ResolveInfo> resolveInfos = + mContext.getPackageManager().queryBroadcastReceiversAsUser( + intent, 0, UserHandle.SYSTEM); + if (resolveInfos == null || resolveInfos.isEmpty()) { + return; // No need to send broadcast. + } + + for (ResolveInfo resolveInfo : resolveInfos) { + Intent intentToSend = new Intent(intent); + intentToSend.setComponent(new ComponentName( + resolveInfo.activityInfo.applicationInfo.packageName, + resolveInfo.activityInfo.name)); + mContext.sendBroadcastAsUser(intentToSend, UserHandle.SYSTEM, + android.Manifest.permission.DUMP); + } } @Override diff --git a/apex/statsd/tests/libstatspull/Android.bp b/apex/statsd/tests/libstatspull/Android.bp index e81396405d31..2d64f190839c 100644 --- a/apex/statsd/tests/libstatspull/Android.bp +++ b/apex/statsd/tests/libstatspull/Android.bp @@ -48,9 +48,13 @@ cc_library_shared { "-Werror", ], shared_libs: [ - "libbinder", + "libbinder_ndk", + "statsd-aidl-ndk_platform", + ], + static_libs: [ + "libstatspull_private", + "libstatssocket_private", "libutils", - "libstatspull", - "libstatssocket", + "libcutils", ], -}
\ No newline at end of file +} diff --git a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp index 22daa8eb6b3e..eb97f6559b6d 100644 --- a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp +++ b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <binder/ProcessState.h> +#include <android/binder_process.h> #include <jni.h> #include <log/log.h> #include <stats_event.h> @@ -24,7 +24,6 @@ #include <thread> using std::this_thread::sleep_for; -using namespace android; namespace { static int32_t sAtomTag; @@ -39,10 +38,8 @@ static void init() { if (!initialized) { initialized = true; // Set up the binder - sp<ProcessState> ps(ProcessState::self()); - ps->setThreadPoolMaxThreadCount(9); - ps->startThreadPool(); - ps->giveThreadPoolName(); + ABinderProcess_setThreadPoolMaxThreadCount(9); + ABinderProcess_startThreadPool(); } } diff --git a/api/current.txt b/api/current.txt index 1227006dbe04..e2d054800d4a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2992,9 +2992,7 @@ package android.accessibilityservice { method public int getNonInteractiveUiTimeoutMillis(); method public android.content.pm.ResolveInfo getResolveInfo(); method public String getSettingsActivityName(); - method @Nullable public android.graphics.drawable.Drawable loadAnimatedImage(@NonNull android.content.Context); method public String loadDescription(android.content.pm.PackageManager); - method @Nullable public String loadHtmlDescription(@NonNull android.content.pm.PackageManager); method public CharSequence loadSummary(android.content.pm.PackageManager); method public void setInteractiveUiTimeoutMillis(@IntRange(from=0) int); method public void setNonInteractiveUiTimeoutMillis(@IntRange(from=0) int); @@ -8189,6 +8187,7 @@ package android.appwidget { field public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth"; field public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight"; field public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth"; + field public static final String OPTION_APPWIDGET_RESTORE_COMPLETED = "appWidgetRestoreCompleted"; } public class AppWidgetProvider extends android.content.BroadcastReceiver { @@ -10120,7 +10119,6 @@ package android.content { method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String); method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); - method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent); method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle); @@ -10328,6 +10326,7 @@ package android.content { method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String); method public void sendOrderedBroadcast(android.content.Intent, String); method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle); + method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, int, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, @Nullable String, @Nullable android.os.Bundle, @Nullable android.os.Bundle); method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle); method @Deprecated public void sendStickyBroadcast(android.content.Intent); method @Deprecated public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle); @@ -27060,7 +27059,7 @@ package android.media { method public void unregisterTransferCallback(@NonNull android.media.MediaRouter2.TransferCallback); } - public static class MediaRouter2.ControllerCallback { + public abstract static class MediaRouter2.ControllerCallback { ctor public MediaRouter2.ControllerCallback(); method public void onControllerUpdated(@NonNull android.media.MediaRouter2.RoutingController); } @@ -27069,7 +27068,7 @@ package android.media { method @Nullable public android.os.Bundle onGetControllerHints(@NonNull android.media.MediaRoute2Info); } - public static class MediaRouter2.RouteCallback { + public abstract static class MediaRouter2.RouteCallback { ctor public MediaRouter2.RouteCallback(); method public void onRoutesAdded(@NonNull java.util.List<android.media.MediaRoute2Info>); method public void onRoutesChanged(@NonNull java.util.List<android.media.MediaRoute2Info>); @@ -27092,7 +27091,7 @@ package android.media { method public void setVolume(int); } - public static class MediaRouter2.TransferCallback { + public abstract static class MediaRouter2.TransferCallback { ctor public MediaRouter2.TransferCallback(); method public void onTransferFailed(@NonNull android.media.MediaRoute2Info); method public void onTransferred(@NonNull android.media.MediaRouter2.RoutingController, @Nullable android.media.MediaRouter2.RoutingController); @@ -27478,6 +27477,7 @@ package android.media { method @Nullable public android.os.Bundle getControlHints(); method @NonNull public java.util.List<java.lang.String> getDeselectableRoutes(); method @NonNull public String getId(); + method @Nullable public CharSequence getName(); method @NonNull public java.util.List<java.lang.String> getSelectableRoutes(); method @NonNull public java.util.List<java.lang.String> getSelectedRoutes(); method @NonNull public java.util.List<java.lang.String> getTransferableRoutes(); @@ -27505,6 +27505,7 @@ package android.media { method @NonNull public android.media.RoutingSessionInfo.Builder removeSelectedRoute(@NonNull String); method @NonNull public android.media.RoutingSessionInfo.Builder removeTransferableRoute(@NonNull String); method @NonNull public android.media.RoutingSessionInfo.Builder setControlHints(@Nullable android.os.Bundle); + method @NonNull public android.media.RoutingSessionInfo.Builder setName(@Nullable CharSequence); method @NonNull public android.media.RoutingSessionInfo.Builder setVolume(int); method @NonNull public android.media.RoutingSessionInfo.Builder setVolumeHandling(int); method @NonNull public android.media.RoutingSessionInfo.Builder setVolumeMax(int); @@ -29356,9 +29357,9 @@ package android.media.tv { public abstract class TvInputService extends android.app.Service { ctor public TvInputService(); method public final android.os.IBinder onBind(android.content.Intent); - method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(String); + method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(@NonNull String); method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(@NonNull String, @NonNull String); - method @Nullable public abstract android.media.tv.TvInputService.Session onCreateSession(String); + method @Nullable public abstract android.media.tv.TvInputService.Session onCreateSession(@NonNull String); method @Nullable public android.media.tv.TvInputService.Session onCreateSession(@NonNull String, @NonNull String); field public static final int PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND = 100; // 0x64 field public static final int PRIORITY_HINT_USE_CASE_TYPE_LIVE = 400; // 0x190 @@ -31105,6 +31106,7 @@ package android.net.wifi { public class ScanResult implements android.os.Parcelable { ctor public ScanResult(@NonNull android.net.wifi.ScanResult); + ctor public ScanResult(); method public int describeContents(); method @NonNull public java.util.List<android.net.wifi.ScanResult.InformationElement> getInformationElements(); method public int getWifiStandard(); @@ -31376,6 +31378,15 @@ package android.net.wifi { field public static final int LINK_SPEED_UNKNOWN = -1; // 0xffffffff } + public static final class WifiInfo.Builder { + ctor public WifiInfo.Builder(); + method @NonNull public android.net.wifi.WifiInfo build(); + method @NonNull public android.net.wifi.WifiInfo.Builder setBssid(@NonNull String); + method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int); + method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int); + method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]); + } + public class WifiManager { method @Deprecated public int addNetwork(android.net.wifi.WifiConfiguration); method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int addNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>); @@ -31559,6 +31570,20 @@ package android.net.wifi { public final class WifiNetworkSuggestion implements android.os.Parcelable { method public int describeContents(); + method @Nullable public android.net.MacAddress getBssid(); + method @Nullable public android.net.wifi.WifiEnterpriseConfig getEnterpriseConfig(); + method @Nullable public String getPassphrase(); + method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfig(); + method @IntRange(from=0) public int getPriority(); + method @Nullable public String getSsid(); + method public boolean isAppInteractionRequired(); + method public boolean isCredentialSharedWithUser(); + method public boolean isEnhancedOpen(); + method public boolean isHiddenSsid(); + method public boolean isInitialAutojoinEnabled(); + method public boolean isMetered(); + method public boolean isUntrusted(); + method public boolean isUserInteractionRequired(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR; } @@ -43425,12 +43450,12 @@ package android.service.controls { public abstract class ControlsProviderService extends android.app.Service { ctor public ControlsProviderService(); - method @Deprecated public void loadAvailableControls(@NonNull java.util.function.Consumer<java.util.List<android.service.controls.Control>>); + method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> createPublisherFor(@NonNull java.util.List<java.lang.String>); + method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> createPublisherForAllAvailable(); + method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> createPublisherForSuggested(); method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); + method public final boolean onUnbind(@NonNull android.content.Intent); method public abstract void performControlAction(@NonNull String, @NonNull android.service.controls.actions.ControlAction, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @NonNull public abstract java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherFor(@NonNull java.util.List<java.lang.String>); - method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForAllAvailable(); - method @Nullable public java.util.concurrent.Flow.Publisher<android.service.controls.Control> publisherForSuggested(); method public static void requestAddControl(@NonNull android.content.Context, @NonNull android.content.ComponentName, @NonNull android.service.controls.Control); field public static final String SERVICE_CONTROLS = "android.service.controls.ControlsProviderService"; field @NonNull public static final String TAG = "ControlsProviderService"; @@ -48146,6 +48171,7 @@ package android.telephony { method public String getMmsUserAgent(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNai(); method public String getNetworkCountryIso(); + method @NonNull public String getNetworkCountryIso(int); method public String getNetworkOperator(); method public String getNetworkOperatorName(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode(); @@ -48213,6 +48239,7 @@ package android.telephony { method public boolean setLine1NumberForDisplay(String, String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setNetworkSelectionModeAutomatic(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(String, boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(@NonNull String, boolean, int); method public boolean setOperatorBrandOverride(String); method public boolean setPreferredNetworkTypeToGlobal(); method public void setPreferredOpportunisticDataSubscription(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); @@ -55493,6 +55520,7 @@ package android.view { public static final class WindowInsets.Type { method public static int captionBar(); + method public static int displayCutout(); method public static int ime(); method public static int mandatorySystemGestures(); method public static int navigationBars(); @@ -56954,6 +56982,7 @@ package android.view.inputmethod { method @NonNull public android.view.inline.InlinePresentationSpec getPresentationSpec(); method @NonNull public String getSource(); method @NonNull public String getType(); + method public boolean isPinned(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestionInfo> CREATOR; field public static final String SOURCE_AUTOFILL = "android:autofill"; diff --git a/api/system-current.txt b/api/system-current.txt index f84b4158da08..ae893b58ee3d 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4944,30 +4944,32 @@ package android.media.tv.tuner { package android.media.tv.tuner.dvr { - public class Dvr implements java.lang.AutoCloseable { - ctor protected Dvr(int); + public class DvrPlayback implements java.lang.AutoCloseable { method public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter); method public void close(); method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings); method public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter); method public int flush(); + method public long read(long); + method public long read(@NonNull byte[], long, long); method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor); method public int start(); method public int stop(); - field public static final int TYPE_PLAYBACK = 1; // 0x1 - field public static final int TYPE_RECORD = 0; // 0x0 - } - - public class DvrPlayback extends android.media.tv.tuner.dvr.Dvr { - method public long read(long); - method public long read(@NonNull byte[], long, long); field public static final int PLAYBACK_STATUS_ALMOST_EMPTY = 2; // 0x2 field public static final int PLAYBACK_STATUS_ALMOST_FULL = 4; // 0x4 field public static final int PLAYBACK_STATUS_EMPTY = 1; // 0x1 field public static final int PLAYBACK_STATUS_FULL = 8; // 0x8 } - public class DvrRecorder extends android.media.tv.tuner.dvr.Dvr { + public class DvrRecorder implements java.lang.AutoCloseable { + method public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter); + method public void close(); + method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings); + method public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter); + method public int flush(); + method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor); + method public int start(); + method public int stop(); method public long write(long); method public long write(@NonNull byte[], long, long); } @@ -7169,7 +7171,6 @@ package android.net.wifi { } public class ScanResult implements android.os.Parcelable { - ctor public ScanResult(); field public static final int CIPHER_CCMP = 3; // 0x3 field public static final int CIPHER_GCMP_256 = 4; // 0x4 field public static final int CIPHER_NONE = 0; // 0x0 @@ -7314,8 +7315,8 @@ package android.net.wifi { method @Deprecated public int getDisableReasonCounter(int); method @Deprecated public long getDisableTime(); method @Deprecated public static int getMaxNetworkSelectionDisableReason(); - method @Deprecated @Nullable public static String getNetworkDisableReasonString(int); method @Deprecated public int getNetworkSelectionDisableReason(); + method @Deprecated @Nullable public static String getNetworkSelectionDisableReasonString(int); method @Deprecated public int getNetworkSelectionStatus(); method @Deprecated @NonNull public String getNetworkStatusString(); method @Deprecated public boolean hasEverConnected(); @@ -7377,15 +7378,6 @@ package android.net.wifi { field public static final int INVALID_RSSI = -127; // 0xffffff81 } - public static final class WifiInfo.Builder { - ctor public WifiInfo.Builder(); - method @NonNull public android.net.wifi.WifiInfo build(); - method @NonNull public android.net.wifi.WifiInfo.Builder setBssid(@NonNull String); - method @NonNull public android.net.wifi.WifiInfo.Builder setNetworkId(int); - method @NonNull public android.net.wifi.WifiInfo.Builder setRssi(int); - method @NonNull public android.net.wifi.WifiInfo.Builder setSsid(@NonNull byte[]); - } - public class WifiManager { method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean); @@ -7431,7 +7423,7 @@ package android.net.wifi { method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean); method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean); - method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMeteredOverridePasspoint(@NonNull String, int); + method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanThrottleEnabled(boolean); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration); @@ -7528,7 +7520,7 @@ package android.net.wifi { } public static interface WifiManager.ScoreChangeCallback { - method public void onScoreChange(int, @NonNull android.net.NetworkScore); + method public void onScoreChange(int, int); method public void onTriggerUpdateOfWifiUsabilityStats(int); } @@ -7554,51 +7546,28 @@ package android.net.wifi { method public void stop(int); } - public class WifiNetworkConnectionStatistics implements android.os.Parcelable { - ctor public WifiNetworkConnectionStatistics(int, int); - ctor public WifiNetworkConnectionStatistics(); - ctor public WifiNetworkConnectionStatistics(android.net.wifi.WifiNetworkConnectionStatistics); - method public int describeContents(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkConnectionStatistics> CREATOR; - field public int numConnection; - field public int numUsage; - } - - public final class WifiNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { - method public boolean satisfiedBy(android.net.NetworkSpecifier); - } - - public final class WifiNetworkSuggestion implements android.os.Parcelable { - method @Nullable public android.net.wifi.hotspot2.PasspointConfiguration getPasspointConfiguration(); - method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration(); - } - - public static final class WifiNetworkSuggestion.Builder { - method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int); - } - - public final class WifiOemMigrationHook { - method @Nullable public static android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData loadFromConfigStore(); - method @NonNull public static android.net.wifi.WifiOemMigrationHook.SettingsMigrationData loadFromSettings(@NonNull android.content.Context); + public final class WifiMigration { + method @Nullable public static android.net.wifi.WifiMigration.ConfigStoreMigrationData loadFromConfigStore(); + method @NonNull public static android.net.wifi.WifiMigration.SettingsMigrationData loadFromSettings(@NonNull android.content.Context); + method public static void removeConfigStore(); } - public static final class WifiOemMigrationHook.ConfigStoreMigrationData implements android.os.Parcelable { + public static final class WifiMigration.ConfigStoreMigrationData implements android.os.Parcelable { method public int describeContents(); method @Nullable public java.util.List<android.net.wifi.WifiConfiguration> getUserSavedNetworkConfigurations(); method @Nullable public android.net.wifi.SoftApConfiguration getUserSoftApConfiguration(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiMigration.ConfigStoreMigrationData> CREATOR; } - public static final class WifiOemMigrationHook.ConfigStoreMigrationData.Builder { - ctor public WifiOemMigrationHook.ConfigStoreMigrationData.Builder(); - method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData build(); - method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData.Builder setUserSavedNetworkConfigurations(@NonNull java.util.List<android.net.wifi.WifiConfiguration>); - method @NonNull public android.net.wifi.WifiOemMigrationHook.ConfigStoreMigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration); + public static final class WifiMigration.ConfigStoreMigrationData.Builder { + ctor public WifiMigration.ConfigStoreMigrationData.Builder(); + method @NonNull public android.net.wifi.WifiMigration.ConfigStoreMigrationData build(); + method @NonNull public android.net.wifi.WifiMigration.ConfigStoreMigrationData.Builder setUserSavedNetworkConfigurations(@NonNull java.util.List<android.net.wifi.WifiConfiguration>); + method @NonNull public android.net.wifi.WifiMigration.ConfigStoreMigrationData.Builder setUserSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration); } - public static final class WifiOemMigrationHook.SettingsMigrationData implements android.os.Parcelable { + public static final class WifiMigration.SettingsMigrationData implements android.os.Parcelable { method public int describeContents(); method @Nullable public String getP2pDeviceName(); method public boolean isP2pFactoryResetPending(); @@ -7608,19 +7577,42 @@ package android.net.wifi { method public boolean isVerboseLoggingEnabled(); method public boolean isWakeUpEnabled(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiOemMigrationHook.SettingsMigrationData> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiMigration.SettingsMigrationData> CREATOR; + } + + public static final class WifiMigration.SettingsMigrationData.Builder { + ctor public WifiMigration.SettingsMigrationData.Builder(); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData build(); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setP2pDeviceName(@Nullable String); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setP2pFactoryResetPending(boolean); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setScanAlwaysAvailable(boolean); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setScanThrottleEnabled(boolean); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setSoftApTimeoutEnabled(boolean); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setVerboseLoggingEnabled(boolean); + method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setWakeUpEnabled(boolean); + } + + public class WifiNetworkConnectionStatistics implements android.os.Parcelable { + ctor public WifiNetworkConnectionStatistics(int, int); + ctor public WifiNetworkConnectionStatistics(); + ctor public WifiNetworkConnectionStatistics(android.net.wifi.WifiNetworkConnectionStatistics); + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkConnectionStatistics> CREATOR; + field public int numConnection; + field public int numUsage; } - public static final class WifiOemMigrationHook.SettingsMigrationData.Builder { - ctor public WifiOemMigrationHook.SettingsMigrationData.Builder(); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData build(); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setP2pDeviceName(@Nullable String); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setP2pFactoryResetPending(boolean); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setScanAlwaysAvailable(boolean); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setScanThrottleEnabled(boolean); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setSoftApTimeoutEnabled(boolean); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setVerboseLoggingEnabled(boolean); - method @NonNull public android.net.wifi.WifiOemMigrationHook.SettingsMigrationData.Builder setWakeUpEnabled(boolean); + public final class WifiNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + method public boolean satisfiedBy(android.net.NetworkSpecifier); + } + + public final class WifiNetworkSuggestion implements android.os.Parcelable { + method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration(); + } + + public static final class WifiNetworkSuggestion.Builder { + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int); } public class WifiScanner { @@ -9939,6 +9931,7 @@ package android.service.autofill.augmented { method @NonNull public android.service.autofill.augmented.FillResponse build(); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow); + method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>); } @@ -9966,28 +9959,6 @@ package android.service.carrier { method @NonNull @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int); } - public abstract class CarrierMessagingServiceWrapper { - ctor public CarrierMessagingServiceWrapper(); - method public boolean bindToCarrierMessagingService(@NonNull android.content.Context, @NonNull String); - method public void disposeConnection(@NonNull android.content.Context); - method public void downloadMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper); - method public void filterSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper); - method public abstract void onServiceReady(); - method public void sendDataSms(@NonNull byte[], int, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper); - method public void sendMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper); - method public void sendMultipartTextSms(@NonNull java.util.List<java.lang.String>, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper); - method public void sendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper); - } - - public abstract static class CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper { - ctor public CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper(); - method public void onDownloadMmsComplete(int); - method public void onFilterComplete(int); - method public void onSendMmsComplete(int, @Nullable byte[]); - method public void onSendMultipartSmsComplete(int, @Nullable int[]); - method public void onSendSmsComplete(int, int); - } - } package android.service.contentcapture { @@ -11451,7 +11422,6 @@ package android.telephony { } public class ServiceState implements android.os.Parcelable { - method @NonNull public android.telephony.ServiceState createLocationInfoSanitizedCopy(boolean); method public void fillInNotifierBundle(@NonNull android.os.Bundle); method public int getDataNetworkType(); method public int getDataRegistrationState(); @@ -11628,7 +11598,7 @@ package android.telephony { public class SubscriptionManager { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean canDisablePhysicalSubscription(); - method public boolean canManageSubscription(@Nullable android.telephony.SubscriptionInfo, @Nullable String); + method public boolean canManageSubscription(@NonNull android.telephony.SubscriptionInfo, @NonNull String); method @NonNull public int[] getActiveAndHiddenSubscriptionIdList(); method @NonNull public int[] getActiveSubscriptionIdList(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String); @@ -11645,7 +11615,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setIconTint(@ColorInt int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(boolean, int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(int, boolean); field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED"; field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff @@ -11738,7 +11708,6 @@ package android.telephony { method public int getMaxNumberOfSimultaneouslyActiveSims(); method public static long getMaxNumberVerificationTimeoutMillis(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getMergedImsisFromGroup(); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getNetworkCountryIso(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState(); method public int getSimApplicationState(); @@ -11796,7 +11765,6 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAlwaysAllowMmsData(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAlwaysReportSignalStrength(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallForwarding(@NonNull android.telephony.CallForwardingInfo); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallWaitingStatus(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); @@ -11809,9 +11777,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setIccLockEnabled(boolean, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(@NonNull String, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPolicyDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean); @@ -11940,45 +11906,6 @@ package android.telephony { field public static final int SRVCC_STATE_HANDOVER_STARTED = 0; // 0x0 } - public class TelephonyRegistryManager { - method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor); - method public void addOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener, @NonNull java.util.concurrent.Executor); - method public void listenForSubscriber(int, @NonNull String, @NonNull String, @NonNull android.telephony.PhoneStateListener, int, boolean); - method public void notifyActiveDataSubIdChanged(int); - method public void notifyBarringInfoChanged(int, int, @NonNull android.telephony.BarringInfo); - method public void notifyCallForwardingChanged(int, boolean); - method public void notifyCallQualityChanged(int, int, @NonNull android.telephony.CallQuality, int); - method public void notifyCallStateChanged(int, int, int, @Nullable String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyCallStateChangedForAllSubscriptions(int, @Nullable String); - method public void notifyCarrierNetworkChange(boolean); - method public void notifyCellInfoChanged(int, @NonNull java.util.List<android.telephony.CellInfo>); - method public void notifyCellLocation(int, @NonNull android.telephony.CellIdentity); - method public void notifyDataActivationStateChanged(int, int, int); - method public void notifyDataActivityChanged(int, int); - method public void notifyDataConnectionForSubscriber(int, int, int, @Nullable android.telephony.PreciseDataConnectionState); - method public void notifyDisconnectCause(int, int, int, int); - method public void notifyDisplayInfoChanged(int, int, @NonNull android.telephony.DisplayInfo); - method public void notifyEmergencyNumberList(int, int); - method public void notifyImsDisconnectCause(int, @NonNull android.telephony.ims.ImsReasonInfo); - method public void notifyMessageWaitingChanged(int, int, boolean); - method public void notifyOpportunisticSubscriptionInfoChanged(); - method public void notifyOutgoingEmergencyCall(int, int, @NonNull android.telephony.emergency.EmergencyNumber); - method public void notifyOutgoingEmergencySms(int, int, @NonNull android.telephony.emergency.EmergencyNumber); - method public void notifyPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability); - method public void notifyPreciseCallState(int, int, int, int, int); - method public void notifyPreciseDataConnectionFailed(int, int, int, @Nullable String, int); - method public void notifyRadioPowerStateChanged(int, int, int); - method public void notifyRegistrationFailed(int, int, @NonNull android.telephony.CellIdentity, @NonNull String, int, int, int); - method public void notifyServiceStateChanged(int, int, @NonNull android.telephony.ServiceState); - method public void notifySignalStrengthChanged(int, int, @NonNull android.telephony.SignalStrength); - method public void notifySrvccStateChanged(int, int); - method public void notifySubscriptionInfoChanged(); - method public void notifyUserMobileDataStateChanged(int, int, boolean); - method public void notifyVoiceActivationStateChanged(int, int, int); - method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener); - method public void removeOnSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); - } - public final class UiccAccessRule implements android.os.Parcelable { ctor public UiccAccessRule(byte[], @Nullable String, long); method public int describeContents(); diff --git a/api/test-current.txt b/api/test-current.txt index 4a9c4d67e481..f25f10807753 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3270,6 +3270,7 @@ package android.service.autofill.augmented { method @NonNull public android.service.autofill.augmented.FillResponse build(); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow); + method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>); method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>); } @@ -3769,7 +3770,6 @@ package android.telephony { method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); method public int getEmergencyNumberDbVersion(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); - method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); @@ -5212,7 +5212,7 @@ package android.view.inputmethod { } public final class InlineSuggestionInfo implements android.os.Parcelable { - method @NonNull public static android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(@NonNull android.view.inline.InlinePresentationSpec, @NonNull String, @Nullable String[]); + method @NonNull public static android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(@NonNull android.view.inline.InlinePresentationSpec, @NonNull String, @Nullable String[], @NonNull String, boolean); } public final class InlineSuggestionsResponse implements android.os.Parcelable { diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp index 95de6c506795..1e200c52a207 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.cpp +++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp @@ -146,6 +146,8 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, struct uhid_event ev = {}; ev.type = UHID_CREATE2; strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name)); + std::string uniq = android::base::StringPrintf("Id: %d", id); + strlcpy(reinterpret_cast<char*>(ev.u.create2.uniq), uniq.c_str(), sizeof(ev.u.create2.uniq)); memcpy(&ev.u.create2.rd_data, descriptor.data(), size * sizeof(ev.u.create2.rd_data[0])); ev.u.create2.rd_size = size; ev.u.create2.bus = bus; diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index 66f5c3908e4b..645dc935fc07 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -36,18 +36,7 @@ cc_library { ], host_supported: true, srcs: [ - "libidmap2/BinaryStreamVisitor.cpp", - "libidmap2/CommandLineOptions.cpp", - "libidmap2/FileUtils.cpp", - "libidmap2/Idmap.cpp", - "libidmap2/Policies.cpp", - "libidmap2/PrettyPrintVisitor.cpp", - "libidmap2/RawPrintVisitor.cpp", - "libidmap2/ResourceMapping.cpp", - "libidmap2/ResourceUtils.cpp", - "libidmap2/Result.cpp", - "libidmap2/XmlParser.cpp", - "libidmap2/ZipFile.cpp", + "libidmap2/**/*.cpp", ], export_include_dirs: ["include"], target: { @@ -61,6 +50,7 @@ cc_library { "libcutils", "libutils", "libziparchive", + "libidmap2_policies", ], }, host: { @@ -73,6 +63,37 @@ cc_library { "libcutils", "libutils", "libziparchive", + "libidmap2_policies", + ], + }, + }, +} + +cc_library { + name: "libidmap2_policies", + defaults: [ + "idmap2_defaults", + ], + host_supported: true, + export_include_dirs: ["libidmap2_policies/include"], + target: { + windows: { + enabled: true, + }, + android: { + static: { + enabled: false, + }, + shared_libs: [ + "libandroidfw", + ], + }, + host: { + shared: { + enabled: false, + }, + static_libs: [ + "libandroidfw", ], }, }, @@ -118,6 +139,7 @@ cc_test { "libutils", "libz", "libziparchive", + "libidmap2_policies", ], }, host: { @@ -129,6 +151,7 @@ cc_test { "liblog", "libutils", "libziparchive", + "libidmap2_policies", ], shared_libs: [ "libz", @@ -162,6 +185,7 @@ cc_binary { "libidmap2", "libutils", "libziparchive", + "libidmap2_policies", ], }, host: { @@ -173,12 +197,14 @@ cc_binary { "liblog", "libutils", "libziparchive", + "libidmap2_policies", ], shared_libs: [ "libz", ], }, }, + } cc_binary { @@ -199,6 +225,7 @@ cc_binary { "libidmap2", "libutils", "libziparchive", + "libidmap2_policies", ], static_libs: [ "libidmap2daidl", @@ -231,3 +258,16 @@ filegroup { ], path: "idmap2d/aidl", } + +aidl_interface { + name: "overlayable_policy_aidl", + srcs: [":overlayable_policy_aidl_files"], +} + +filegroup { + name: "overlayable_policy_aidl_files", + srcs: [ + "idmap2d/aidl/android/os/OverlayablePolicy.aidl", + ], + path: "idmap2d/aidl", +} diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp index 3ff6d3514331..9682b6ead293 100644 --- a/cmds/idmap2/idmap2/Create.cpp +++ b/cmds/idmap2/idmap2/Create.cpp @@ -20,15 +20,14 @@ #include <fstream> #include <memory> #include <ostream> -#include <sstream> -#include <string> #include <vector> +#include "androidfw/ResourceTypes.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/CommandLineOptions.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" -#include "idmap2/Policies.h" +#include "idmap2/PolicyUtils.h" #include "idmap2/SysTrace.h" using android::ApkAssets; @@ -36,14 +35,15 @@ using android::idmap2::BinaryStreamVisitor; using android::idmap2::CommandLineOptions; using android::idmap2::Error; using android::idmap2::Idmap; -using android::idmap2::PoliciesToBitmask; -using android::idmap2::PolicyBitmask; -using android::idmap2::PolicyFlags; using android::idmap2::Result; using android::idmap2::Unit; using android::idmap2::utils::kIdmapFilePermissionMask; +using android::idmap2::utils::PoliciesToBitmaskResult; using android::idmap2::utils::UidHasWriteAccessToPath; +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + Result<Unit> Create(const std::vector<std::string>& args) { SYSTRACE << "Create " << args; std::string target_apk_path; @@ -78,7 +78,7 @@ Result<Unit> Create(const std::vector<std::string>& args) { } PolicyBitmask fulfilled_policies = 0; - auto conv_result = PoliciesToBitmask(policies); + auto conv_result = PoliciesToBitmaskResult(policies); if (conv_result) { fulfilled_policies |= *conv_result; } else { @@ -86,7 +86,7 @@ Result<Unit> Create(const std::vector<std::string>& args) { } if (fulfilled_policies == 0) { - fulfilled_policies |= PolicyFlags::POLICY_PUBLIC; + fulfilled_policies |= PolicyFlags::PUBLIC; } const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp index 0b0541fb6221..ba4ca62826b6 100644 --- a/cmds/idmap2/idmap2/CreateMultiple.cpp +++ b/cmds/idmap2/idmap2/CreateMultiple.cpp @@ -20,8 +20,6 @@ #include <fstream> #include <memory> #include <ostream> -#include <sstream> -#include <string> #include <vector> #include "android-base/stringprintf.h" @@ -30,7 +28,9 @@ #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" #include "idmap2/Policies.h" +#include "idmap2/PolicyUtils.h" #include "idmap2/SysTrace.h" +#include "Commands.h" using android::ApkAssets; using android::base::StringPrintf; @@ -38,13 +38,11 @@ using android::idmap2::BinaryStreamVisitor; using android::idmap2::CommandLineOptions; using android::idmap2::Error; using android::idmap2::Idmap; -using android::idmap2::PoliciesToBitmask; -using android::idmap2::PolicyBitmask; -using android::idmap2::PolicyFlags; using android::idmap2::Result; using android::idmap2::Unit; using android::idmap2::utils::kIdmapCacheDir; using android::idmap2::utils::kIdmapFilePermissionMask; +using android::idmap2::utils::PoliciesToBitmaskResult; using android::idmap2::utils::UidHasWriteAccessToPath; Result<Unit> CreateMultiple(const std::vector<std::string>& args) { @@ -80,7 +78,7 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) { } PolicyBitmask fulfilled_policies = 0; - auto conv_result = PoliciesToBitmask(policies); + auto conv_result = PoliciesToBitmaskResult(policies); if (conv_result) { fulfilled_policies |= *conv_result; } else { @@ -88,7 +86,7 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) { } if (fulfilled_policies == 0) { - fulfilled_policies |= PolicyFlags::POLICY_PUBLIC; + fulfilled_policies |= PolicyFlags::PUBLIC; } const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); @@ -105,32 +103,34 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) { continue; } - const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); - if (!overlay_apk) { - LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str(); - continue; - } - - const auto idmap = - Idmap::FromApkAssets(*target_apk, *overlay_apk, fulfilled_policies, !ignore_overlayable); - if (!idmap) { - LOG(WARNING) << "failed to create idmap"; - continue; - } - - umask(kIdmapFilePermissionMask); - std::ofstream fout(idmap_path); - if (fout.fail()) { - LOG(WARNING) << "failed to open idmap path " << idmap_path.c_str(); - continue; - } - - BinaryStreamVisitor visitor(fout); - (*idmap)->accept(&visitor); - fout.close(); - if (fout.fail()) { - LOG(WARNING) << "failed to write to idmap path %s" << idmap_path.c_str(); - continue; + if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}))) { + const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); + if (!overlay_apk) { + LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str(); + continue; + } + + const auto idmap = + Idmap::FromApkAssets(*target_apk, *overlay_apk, fulfilled_policies, !ignore_overlayable); + if (!idmap) { + LOG(WARNING) << "failed to create idmap"; + continue; + } + + umask(kIdmapFilePermissionMask); + std::ofstream fout(idmap_path); + if (fout.fail()) { + LOG(WARNING) << "failed to open idmap path " << idmap_path.c_str(); + continue; + } + + BinaryStreamVisitor visitor(fout); + (*idmap)->accept(&visitor); + fout.close(); + if (fout.fail()) { + LOG(WARNING) << "failed to write to idmap path %s" << idmap_path.c_str(); + continue; + } } idmap_paths.emplace_back(idmap_path); diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index b4fdd0b8a94d..da0453216f03 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -20,7 +20,6 @@ #include <memory> #include <ostream> #include <set> -#include <sstream> #include <string> #include <utility> #include <vector> @@ -34,25 +33,24 @@ #include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "idmap2/XmlParser.h" -#include "idmap2/ZipFile.h" using android::idmap2::CommandLineOptions; using android::idmap2::Error; using android::idmap2::Idmap; -using android::idmap2::kPolicyOdm; -using android::idmap2::kPolicyOem; -using android::idmap2::kPolicyProduct; -using android::idmap2::kPolicyPublic; -using android::idmap2::kPolicySystem; -using android::idmap2::kPolicyVendor; -using android::idmap2::PolicyBitmask; -using android::idmap2::PolicyFlags; using android::idmap2::Result; using android::idmap2::Unit; +using android::idmap2::policy::kPolicyOdm; +using android::idmap2::policy::kPolicyOem; +using android::idmap2::policy::kPolicyProduct; +using android::idmap2::policy::kPolicyPublic; +using android::idmap2::policy::kPolicySystem; +using android::idmap2::policy::kPolicyVendor; using android::idmap2::utils::ExtractOverlayManifestInfo; using android::idmap2::utils::FindFiles; using android::idmap2::utils::OverlayManifestInfo; +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; + namespace { struct InputOverlay { diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index 4aabf8399a25..f84e4b5f2575 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -33,7 +33,6 @@ #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" -#include "idmap2/Policies.h" #include "idmap2/SysTrace.h" #include "utils/String8.h" @@ -42,11 +41,12 @@ using android::binder::Status; using android::idmap2::BinaryStreamVisitor; using android::idmap2::Idmap; using android::idmap2::IdmapHeader; -using android::idmap2::PolicyBitmask; using android::idmap2::utils::kIdmapCacheDir; using android::idmap2::utils::kIdmapFilePermissionMask; using android::idmap2::utils::UidHasWriteAccessToPath; +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; + namespace { Status ok() { diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl index cd474c0fe056..f4cf65134023 100644 --- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl +++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl @@ -20,14 +20,6 @@ package android.os; * @hide */ interface IIdmap2 { - const int POLICY_PUBLIC = 0x00000001; - const int POLICY_SYSTEM_PARTITION = 0x00000002; - const int POLICY_VENDOR_PARTITION = 0x00000004; - const int POLICY_PRODUCT_PARTITION = 0x00000008; - const int POLICY_SIGNATURE = 0x00000010; - const int POLICY_ODM_PARTITION = 0x00000020; - const int POLICY_OEM_PARTITION = 0x00000040; - @utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId); boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId); boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies, diff --git a/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl index c4e41c87564f..02b27a8800b6 100644 --- a/packages/Incremental/NativeAdbDataLoader/src/com/android/incremental/nativeadb/NativeAdbDataLoaderService.java +++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl @@ -14,21 +14,19 @@ * limitations under the License. */ -package com.android.incremental.nativeadb; +package android.os; -import android.annotation.NonNull; -import android.content.pm.DataLoaderParams; -import android.service.dataloader.DataLoaderService; - -/** This code is used for testing only. */ -public class NativeAdbDataLoaderService extends DataLoaderService { - public static final String TAG = "NativeAdbDataLoaderService"; - static { - System.loadLibrary("nativeadbdataloaderservice_jni"); - } - - @Override - public DataLoader onCreateDataLoader(@NonNull DataLoaderParams dataLoaderParams) { - return null; - } +/** + * @see ResourcesTypes.h ResTable_overlayable_policy_header::PolicyFlags + * @hide + */ +interface OverlayablePolicy { + const int PUBLIC = 0x00000001; + const int SYSTEM_PARTITION = 0x00000002; + const int VENDOR_PARTITION = 0x00000004; + const int PRODUCT_PARTITION = 0x00000008; + const int SIGNATURE = 0x00000010; + const int ODM_PARTITION = 0x00000020; + const int OEM_PARTITION = 0x00000040; + const int ACTOR_SIGNATURE = 0x00000080; } diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index d4a0c3221c20..2e4836e297ec 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -73,7 +73,6 @@ #include "androidfw/ApkAssets.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" -#include "idmap2/Policies.h" #include "idmap2/ResourceMapping.h" namespace android::idmap2 { diff --git a/cmds/idmap2/include/idmap2/PolicyUtils.h b/cmds/idmap2/include/idmap2/PolicyUtils.h new file mode 100644 index 000000000000..b95b8b420658 --- /dev/null +++ b/cmds/idmap2/include/idmap2/PolicyUtils.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef IDMAP2_INCLUDE_IDMAP2_POLICYUTILS_H_ +#define IDMAP2_INCLUDE_IDMAP2_POLICYUTILS_H_ + +#include <string> +#include <vector> + +#include "androidfw/ResourceTypes.h" +#include "idmap2/Policies.h" +#include "idmap2/Result.h" + +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; + +namespace android::idmap2::utils { + +// Returns a Result object containing a policy flag bitmask built from a list of policy strings. +// On error will contain a human readable message listing the invalid policies. +Result<PolicyBitmask> PoliciesToBitmaskResult(const std::vector<std::string>& policies); + +// Converts a bitmask of policy flags into a list of their string representation as would be written +// into XML +std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask); + +} // namespace android::idmap2::utils + +#endif // IDMAP2_INCLUDE_IDMAP2_POLICYUTILS_H_ diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h index 86dfab20e448..5869409e7db9 100644 --- a/cmds/idmap2/include/idmap2/ResourceMapping.h +++ b/cmds/idmap2/include/idmap2/ResourceMapping.h @@ -30,6 +30,8 @@ using android::idmap2::utils::OverlayManifestInfo; +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; + namespace android::idmap2 { struct TargetValue { diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp deleted file mode 100644 index 495fe615a91f..000000000000 --- a/cmds/idmap2/libidmap2/Policies.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "idmap2/Policies.h" - -#include <iterator> -#include <string> -#include <unordered_map> -#include <vector> - -#include "androidfw/ResourceTypes.h" -#include "idmap2/Idmap.h" -#include "idmap2/Result.h" - -namespace android::idmap2 { - -Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies) { - static const std::unordered_map<android::StringPiece, PolicyFlags> kStringToFlag = { - {kPolicyOdm, PolicyFlags::POLICY_ODM_PARTITION}, - {kPolicyOem, PolicyFlags::POLICY_OEM_PARTITION}, - {kPolicyPublic, PolicyFlags::POLICY_PUBLIC}, - {kPolicyProduct, PolicyFlags::POLICY_PRODUCT_PARTITION}, - {kPolicySignature, PolicyFlags::POLICY_SIGNATURE}, - {kPolicySystem, PolicyFlags::POLICY_SYSTEM_PARTITION}, - {kPolicyVendor, PolicyFlags::POLICY_VENDOR_PARTITION}, - }; - - PolicyBitmask bitmask = 0; - for (const std::string& policy : policies) { - const auto iter = kStringToFlag.find(policy); - if (iter != kStringToFlag.end()) { - bitmask |= iter->second; - } else { - return Error("unknown policy \"%s\"", policy.c_str()); - } - } - - return Result<PolicyBitmask>(bitmask); -} - -std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) { - std::vector<std::string> policies; - - if ((bitmask & PolicyFlags::POLICY_ODM_PARTITION) != 0) { - policies.emplace_back(kPolicyOdm); - } - - if ((bitmask & PolicyFlags::POLICY_OEM_PARTITION) != 0) { - policies.emplace_back(kPolicyOem); - } - - if ((bitmask & PolicyFlags::POLICY_PUBLIC) != 0) { - policies.emplace_back(kPolicyPublic); - } - - if ((bitmask & PolicyFlags::POLICY_PRODUCT_PARTITION) != 0) { - policies.emplace_back(kPolicyProduct); - } - - if ((bitmask & PolicyFlags::POLICY_SIGNATURE) != 0) { - policies.emplace_back(kPolicySignature); - } - - if ((bitmask & PolicyFlags::POLICY_SYSTEM_PARTITION) != 0) { - policies.emplace_back(kPolicySystem); - } - - if ((bitmask & PolicyFlags::POLICY_VENDOR_PARTITION) != 0) { - policies.emplace_back(kPolicyVendor); - } - - return policies; -} - -} // namespace android::idmap2 diff --git a/cmds/idmap2/libidmap2/PolicyUtils.cpp b/cmds/idmap2/libidmap2/PolicyUtils.cpp new file mode 100644 index 000000000000..fc5182af61c1 --- /dev/null +++ b/cmds/idmap2/libidmap2/PolicyUtils.cpp @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#include "include/idmap2/PolicyUtils.h" + +#include <sstream> + +#include "android-base/strings.h" +#include "idmap2/Policies.h" + +using android::idmap2::policy::kPolicyStringToFlag; + +namespace android::idmap2::utils { + +Result<PolicyBitmask> PoliciesToBitmaskResult(const std::vector<std::string>& policies) { + std::vector<std::string> unknown_policies; + PolicyBitmask bitmask = 0; + for (const std::string& policy : policies) { + const auto result = std::find_if(kPolicyStringToFlag.begin(), kPolicyStringToFlag.end(), + [policy](const auto& it) { return policy == it.first; }); + if (result != kPolicyStringToFlag.end()) { + bitmask |= result->second; + } else { + unknown_policies.emplace_back(policy.empty() ? "empty" : policy); + } + } + + if (unknown_policies.empty()) { + return Result<PolicyBitmask>(bitmask); + } + + auto prefix = unknown_policies.size() == 1 ? "policy" : "policies"; + return Error("unknown %s: \"%s\"", prefix, android::base::Join(unknown_policies, ",").c_str()); +} + +std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) { + std::vector<std::string> policies; + + for (const auto& policy : kPolicyStringToFlag) { + if ((bitmask & policy.second) != 0) { + policies.emplace_back(policy.first.to_string()); + } + } + + return policies; +} + +} // namespace android::idmap2::utils diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp index 43cfec3f9cf9..f82c8f1af713 100644 --- a/cmds/idmap2/libidmap2/ResourceMapping.cpp +++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp @@ -24,11 +24,16 @@ #include <vector> #include "android-base/stringprintf.h" +#include "androidfw/ResourceTypes.h" +#include "idmap2/PolicyUtils.h" #include "idmap2/ResourceUtils.h" using android::base::StringPrintf; +using android::idmap2::utils::BitmaskToPolicies; using android::idmap2::utils::IsReference; using android::idmap2::utils::ResToTypeEntryName; +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; namespace android::idmap2 { @@ -55,9 +60,8 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package, const PolicyBitmask& fulfilled_policies, const ResourceId& target_resource) { static constexpr const PolicyBitmask sDefaultPolicies = - PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION | - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION | - PolicyFlags::POLICY_PRODUCT_PARTITION | PolicyFlags::POLICY_SIGNATURE; + PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION | + PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE; // If the resource does not have an overlayable definition, allow the resource to be overlaid if // the overlay is preinstalled or signed with the same signature as the target. diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h index 87edd3506d33..4973b7638d10 100644 --- a/cmds/idmap2/include/idmap2/Policies.h +++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h @@ -14,18 +14,22 @@ * limitations under the License. */ +#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ +#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ + +#include <array> #include <string> #include <vector> -#include "Result.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" -#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ -#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; -namespace android::idmap2 { +namespace android::idmap2::policy { +constexpr const char* kPolicyActor = "actor"; constexpr const char* kPolicyOdm = "odm"; constexpr const char* kPolicyOem = "oem"; constexpr const char* kPolicyProduct = "product"; @@ -34,15 +38,16 @@ constexpr const char* kPolicySignature = "signature"; constexpr const char* kPolicySystem = "system"; constexpr const char* kPolicyVendor = "vendor"; -using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags; -using PolicyBitmask = uint32_t; - -// Parses the string representations of policies into a bitmask. -Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies); - -// Retrieves the string representations of policies in the bitmask. -std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask); - -} // namespace android::idmap2 +inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = { + std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE}, + {kPolicyOdm, PolicyFlags::ODM_PARTITION}, + {kPolicyOem, PolicyFlags::OEM_PARTITION}, + {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION}, + {kPolicyPublic, PolicyFlags::PUBLIC}, + {kPolicySignature, PolicyFlags::SIGNATURE}, + {kPolicySystem, PolicyFlags::SYSTEM_PARTITION}, + {kPolicyVendor, PolicyFlags::VENDOR_PARTITION}, +}; +} // namespace android::idmap2::policy #endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp index b535f30de1f5..d896cf9c11ba 100644 --- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp +++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp @@ -34,6 +34,7 @@ #include <string> #include <vector> +#include "R.h" #include "TestHelpers.h" #include "androidfw/PosixUtils.h" #include "gmock/gmock.h" @@ -127,10 +128,14 @@ TEST_F(Idmap2BinaryTests, Dump) { // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; - ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos); - ASSERT_NE(result->stdout.find("0x7f02000c -> 0x7f020000 string/str1"), std::string::npos); - ASSERT_NE(result->stdout.find("0x7f02000e -> 0x7f020001 string/str3"), std::string::npos); - ASSERT_NE(result->stdout.find("0x7f02000f -> 0x7f020002 string/str4"), std::string::npos); + ASSERT_NE(result->stdout.find(R::target::integer::literal::int1 + " -> 0x7f010000 integer/int1"), + std::string::npos); + ASSERT_NE(result->stdout.find(R::target::string::literal::str1 + " -> 0x7f020000 string/str1"), + std::string::npos); + ASSERT_NE(result->stdout.find(R::target::string::literal::str3 + " -> 0x7f020001 string/str3"), + std::string::npos); + ASSERT_NE(result->stdout.find(R::target::string::literal::str4 + " -> 0x7f020002 string/str4"), + std::string::npos); // clang-format off result = ExecuteBinary({"idmap2", @@ -297,7 +302,7 @@ TEST_F(Idmap2BinaryTests, Lookup) { "lookup", "--idmap-path", GetIdmapPath(), "--config", "", - "--resid", "0x7f02000c"}); // string/str1 + "--resid", R::target::string::literal::str1}); // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index a2c156063757..87da36c01192 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -22,6 +22,8 @@ #include <utility> #include <vector> +#include "R.h" +#include "TestConstants.h" #include "TestHelpers.h" #include "android-base/macros.h" #include "androidfw/ApkAssets.h" @@ -36,6 +38,8 @@ using android::Res_value; using ::testing::IsNull; using ::testing::NotNull; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace android::idmap2 { #define ASSERT_TARGET_ENTRY(entry, target_resid, type, value) \ @@ -168,7 +172,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) { std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage(); auto& idmap = *idmap_result; @@ -177,8 +181,8 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U); - ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x76a20829); - ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xc054fb26); + ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC); + ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC); ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path); ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path); } @@ -220,7 +224,7 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssets) { std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage(); auto& idmap = *idmap_result; @@ -234,17 +238,21 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssets) { const auto& target_entries = data->GetTargetEntries(); ASSERT_EQ(target_entries.size(), 4U); - ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f010000); - ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020000); - ASSERT_TARGET_ENTRY(target_entries[2], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001); - ASSERT_TARGET_ENTRY(target_entries[3], 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020002); + ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1, + Res_value::TYPE_DYNAMIC_REFERENCE, R::overlay::integer::int1); + ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay::string::str1); + ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay::string::str3); + ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay::string::str4); const auto& overlay_entries = data->GetOverlayEntries(); ASSERT_EQ(target_entries.size(), 4U); - ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f010000, 0x7f010000); - ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x7f020000, 0x7f02000c); - ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x7f020001, 0x7f02000e); - ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x7f020002, 0x7f02000f); + ASSERT_OVERLAY_ENTRY(overlay_entries[0], R::overlay::integer::int1, R::target::integer::int1); + ASSERT_OVERLAY_ENTRY(overlay_entries[1], R::overlay::string::str1, R::target::string::str1); + ASSERT_OVERLAY_ENTRY(overlay_entries[2], R::overlay::string::str3, R::target::string::str3); + ASSERT_OVERLAY_ENTRY(overlay_entries[3], R::overlay::string::str4, R::target::string::str4); } TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) { @@ -257,7 +265,7 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) { std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + auto idmap_result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_TRUE(idmap_result) << idmap_result.GetErrorMessage(); auto& idmap = *idmap_result; @@ -271,17 +279,25 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) { const auto& target_entries = data->GetTargetEntries(); ASSERT_EQ(target_entries.size(), 4U); - ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00010000); - ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020000); - ASSERT_TARGET_ENTRY(target_entries[2], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020001); - ASSERT_TARGET_ENTRY(target_entries[3], 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020002); + ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1, + Res_value::TYPE_DYNAMIC_REFERENCE, R::overlay_shared::integer::int1); + ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay_shared::string::str1); + ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay_shared::string::str3); + ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay_shared::string::str4); const auto& overlay_entries = data->GetOverlayEntries(); ASSERT_EQ(target_entries.size(), 4U); - ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x00010000, 0x7f010000); - ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x00020000, 0x7f02000c); - ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x00020001, 0x7f02000e); - ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x00020002, 0x7f02000f); + ASSERT_OVERLAY_ENTRY(overlay_entries[0], R::overlay_shared::integer::int1, + R::target::integer::int1); + ASSERT_OVERLAY_ENTRY(overlay_entries[1], R::overlay_shared::string::str1, + R::target::string::str1); + ASSERT_OVERLAY_ENTRY(overlay_entries[2], R::overlay_shared::string::str3, + R::target::string::str3); + ASSERT_OVERLAY_ENTRY(overlay_entries[3], R::overlay_shared::string::str4, + R::target::string::str4); } TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) { @@ -290,7 +306,7 @@ TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) { info.target_name = "TestResources"; info.resource_mapping = 0x7f030001; // xml/overlays_different_packages auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", info, - PolicyFlags::POLICY_PUBLIC, + PolicyFlags::PUBLIC, /* enforce_overlayable */ false); ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage(); @@ -298,14 +314,14 @@ TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) { const auto& target_entries = data->GetTargetEntries(); ASSERT_EQ(target_entries.size(), 2U); - ASSERT_TARGET_ENTRY(target_entries[0], 0x7f02000c, Res_value::TYPE_REFERENCE, - 0x0104000a); // string/str1 -> android:string/ok - ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, - 0x7f020001); // string/str3 -> string/str4 + ASSERT_TARGET_ENTRY(target_entries[0], R::target::string::str1, Res_value::TYPE_REFERENCE, + 0x0104000a); // -> android:string/ok + ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay::string::str3); const auto& overlay_entries = data->GetOverlayEntries(); ASSERT_EQ(overlay_entries.size(), 1U); - ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x7f020001, 0x7f02000e); // string/str3 <- string/str4 + ASSERT_OVERLAY_ENTRY(overlay_entries[0], R::overlay::string::str3, R::target::string::str3); } TEST(IdmapTests, CreateIdmapDataInlineResources) { @@ -314,7 +330,7 @@ TEST(IdmapTests, CreateIdmapDataInlineResources) { info.target_name = "TestResources"; info.resource_mapping = 0x7f030002; // xml/overlays_inline auto idmap_data = TestIdmapDataFromApkAssets("/target/target.apk", "/overlay/overlay.apk", info, - PolicyFlags::POLICY_PUBLIC, + PolicyFlags::PUBLIC, /* enforce_overlayable */ false); ASSERT_TRUE(idmap_data) << idmap_data.GetErrorMessage(); @@ -323,10 +339,10 @@ TEST(IdmapTests, CreateIdmapDataInlineResources) { constexpr size_t overlay_string_pool_size = 8U; const auto& target_entries = data->GetTargetEntries(); ASSERT_EQ(target_entries.size(), 2U); - ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_INT_DEC, - 73U); // integer/int1 -> 73 - ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_STRING, - overlay_string_pool_size + 0U); // string/str1 -> "Hello World" + ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1, Res_value::TYPE_INT_DEC, + 73U); // -> 73 + ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_STRING, + overlay_string_pool_size + 0U); // -> "Hello World" const auto& overlay_entries = data->GetOverlayEntries(); ASSERT_EQ(overlay_entries.size(), 0U); @@ -346,7 +362,7 @@ TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) { std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - const auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + const auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_FALSE(result); } @@ -362,7 +378,7 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + auto result = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_TRUE(result); const auto idmap = std::move(*result); diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp index eca74045f428..1b2775939886 100644 --- a/cmds/idmap2/tests/PoliciesTests.cpp +++ b/cmds/idmap2/tests/PoliciesTests.cpp @@ -17,76 +17,96 @@ #include <string> #include "TestHelpers.h" +#include "androidfw/ResourceTypes.h" #include "gtest/gtest.h" -#include "idmap2/Policies.h" +#include "idmap2/PolicyUtils.h" -using android::idmap2::PolicyBitmask; -using android::idmap2::PolicyFlags; +using android::idmap2::utils::BitmaskToPolicies; +using android::idmap2::utils::PoliciesToBitmaskResult; + +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; namespace android::idmap2 { -TEST(PoliciesTests, PoliciesToBitmasks) { - const auto bitmask1 = PoliciesToBitmask({"system"}); +TEST(PoliciesTests, PoliciesToBitmaskResults) { + const auto bitmask1 = PoliciesToBitmaskResult({"system"}); ASSERT_TRUE(bitmask1); - ASSERT_EQ(*bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION); + ASSERT_EQ(*bitmask1, PolicyFlags::SYSTEM_PARTITION); - const auto bitmask2 = PoliciesToBitmask({"system", "vendor"}); + const auto bitmask2 = PoliciesToBitmaskResult({"system", "vendor"}); ASSERT_TRUE(bitmask2); - ASSERT_EQ(*bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION); + ASSERT_EQ(*bitmask2, PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION); - const auto bitmask3 = PoliciesToBitmask({"vendor", "system"}); + const auto bitmask3 = PoliciesToBitmaskResult({"vendor", "system"}); ASSERT_TRUE(bitmask3); - ASSERT_EQ(*bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION); + ASSERT_EQ(*bitmask3, PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION); - const auto bitmask4 = PoliciesToBitmask({"odm", "oem", "public", "product", "system", "vendor"}); + const auto bitmask4 = + PoliciesToBitmaskResult({"odm", "oem", "public", "product", "system", "vendor"}); ASSERT_TRUE(bitmask4); - ASSERT_EQ(*bitmask4, PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION | - PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION | - PolicyFlags::POLICY_SYSTEM_PARTITION | - PolicyFlags::POLICY_VENDOR_PARTITION); + ASSERT_EQ(*bitmask4, PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | + PolicyFlags::PUBLIC | PolicyFlags::PRODUCT_PARTITION | + PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION); - const auto bitmask5 = PoliciesToBitmask({"system", "system", "system"}); + const auto bitmask5 = PoliciesToBitmaskResult({"system", "system", "system"}); ASSERT_TRUE(bitmask5); - ASSERT_EQ(*bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION); + ASSERT_EQ(*bitmask5, PolicyFlags::SYSTEM_PARTITION); - const auto bitmask6 = PoliciesToBitmask({""}); + const auto bitmask6 = PoliciesToBitmaskResult({""}); ASSERT_FALSE(bitmask6); - const auto bitmask7 = PoliciesToBitmask({"foo"}); + const auto bitmask7 = PoliciesToBitmaskResult({"foo"}); ASSERT_FALSE(bitmask7); - const auto bitmask8 = PoliciesToBitmask({"system", "foo"}); + const auto bitmask8 = PoliciesToBitmaskResult({"system", "foo"}); ASSERT_FALSE(bitmask8); - const auto bitmask9 = PoliciesToBitmask({"system", ""}); + const auto bitmask9 = PoliciesToBitmaskResult({"system", ""}); ASSERT_FALSE(bitmask9); - const auto bitmask10 = PoliciesToBitmask({"system "}); + const auto bitmask10 = PoliciesToBitmaskResult({"system "}); ASSERT_FALSE(bitmask10); + + const auto bitmask11 = PoliciesToBitmaskResult({"signature"}); + ASSERT_TRUE(bitmask11); + ASSERT_EQ(*bitmask11, PolicyFlags::SIGNATURE); + + const auto bitmask12 = PoliciesToBitmaskResult({"actor"}); + ASSERT_TRUE(bitmask12); + ASSERT_EQ(*bitmask12, PolicyFlags::ACTOR_SIGNATURE); } TEST(PoliciesTests, BitmaskToPolicies) { - const auto policies1 = BitmaskToPolicies(PolicyFlags::POLICY_PUBLIC); + const auto policies1 = BitmaskToPolicies(PolicyFlags::PUBLIC); ASSERT_EQ(1, policies1.size()); ASSERT_EQ(policies1[0], "public"); - const auto policies2 = BitmaskToPolicies(PolicyFlags::POLICY_SYSTEM_PARTITION | - PolicyFlags::POLICY_VENDOR_PARTITION); + const auto policies2 = + BitmaskToPolicies(PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION); ASSERT_EQ(2, policies2.size()); ASSERT_EQ(policies2[0], "system"); ASSERT_EQ(policies2[1], "vendor"); - const auto policies3 = BitmaskToPolicies( - PolicyFlags::POLICY_ODM_PARTITION | PolicyFlags::POLICY_OEM_PARTITION | - PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION | - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION); + const auto policies3 = + BitmaskToPolicies(PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | + PolicyFlags::PUBLIC | PolicyFlags::PRODUCT_PARTITION | + PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION); ASSERT_EQ(2, policies2.size()); ASSERT_EQ(policies3[0], "odm"); ASSERT_EQ(policies3[1], "oem"); - ASSERT_EQ(policies3[2], "public"); - ASSERT_EQ(policies3[3], "product"); + ASSERT_EQ(policies3[2], "product"); + ASSERT_EQ(policies3[3], "public"); ASSERT_EQ(policies3[4], "system"); ASSERT_EQ(policies3[5], "vendor"); + + const auto policies4 = BitmaskToPolicies(PolicyFlags::SIGNATURE); + ASSERT_EQ(1, policies4.size()); + ASSERT_EQ(policies4[0], "signature"); + + const auto policies5 = BitmaskToPolicies(PolicyFlags::ACTOR_SIGNATURE); + ASSERT_EQ(1, policies5.size()); + ASSERT_EQ(policies5[0], "actor"); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp index 1d34e42e188d..9a10079772bf 100644 --- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp @@ -18,19 +18,22 @@ #include <sstream> #include <string> +#include "R.h" #include "TestHelpers.h" #include "androidfw/ApkAssets.h" #include "androidfw/Idmap.h" +#include "androidfw/ResourceTypes.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "idmap2/Idmap.h" -#include "idmap2/Policies.h" #include "idmap2/PrettyPrintVisitor.h" using ::testing::NotNull; using android::ApkAssets; -using android::idmap2::PolicyBitmask; + +using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; namespace android::idmap2 { @@ -43,7 +46,7 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) { std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_TRUE(idmap); @@ -53,7 +56,8 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) { ASSERT_NE(stream.str().find("target apk path : "), std::string::npos); ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos); - ASSERT_NE(stream.str().find("0x7f010000 -> 0x7f010000 integer/int1\n"), std::string::npos); + ASSERT_NE(stream.str().find(R::target::integer::literal::int1 + " -> 0x7f010000 integer/int1\n"), + std::string::npos); } TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitorWithoutAccessToApks) { diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h new file mode 100644 index 000000000000..aed263a49aa3 --- /dev/null +++ b/cmds/idmap2/tests/R.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IDMAP2_TESTS_R_H +#define IDMAP2_TESTS_R_H + +#include <idmap2/ResourceUtils.h> + +namespace android::idmap2 { + +static std::string hexify(ResourceId id) { + std::stringstream stream; + stream << std::hex << static_cast<uint32_t>(id); + return stream.str(); +} + +// clang-format off +namespace R::target { + namespace integer { + constexpr ResourceId int1 = 0x7f010000; + + namespace literal { + inline const std::string int1 = hexify(R::target::integer::int1); + } + } + + namespace string { + constexpr ResourceId not_overlayable = 0x7f020003; + constexpr ResourceId other = 0x7f020004; + constexpr ResourceId policy_actor = 0x7f020005; + constexpr ResourceId policy_odm = 0x7f020006; + constexpr ResourceId policy_oem = 0x7f020007; + constexpr ResourceId policy_product = 0x7f020008; + constexpr ResourceId policy_public = 0x7f020009; + constexpr ResourceId policy_signature = 0x7f02000a; + constexpr ResourceId policy_system = 0x7f02000b; + constexpr ResourceId policy_system_vendor = 0x7f02000c; + constexpr ResourceId str1 = 0x7f02000d; + constexpr ResourceId str3 = 0x7f02000f; + constexpr ResourceId str4 = 0x7f020010; + + namespace literal { + inline const std::string str1 = hexify(R::target::string::str1); + inline const std::string str3 = hexify(R::target::string::str3); + inline const std::string str4 = hexify(R::target::string::str4); + } + } +} + +namespace R::overlay { + namespace integer { + constexpr ResourceId int1 = 0x7f010000; + } + namespace string { + constexpr ResourceId str1 = 0x7f020000; + constexpr ResourceId str3 = 0x7f020001; + constexpr ResourceId str4 = 0x7f020002; + } +} + +namespace R::overlay_shared { + namespace integer { + constexpr ResourceId int1 = 0x00010000; + } + namespace string { + constexpr ResourceId str1 = 0x00020000; + constexpr ResourceId str3 = 0x00020001; + constexpr ResourceId str4 = 0x00020002; + } +} + +namespace R::system_overlay::string { + constexpr ResourceId policy_public = 0x7f010000; + constexpr ResourceId policy_system = 0x7f010001; + constexpr ResourceId policy_system_vendor = 0x7f010002; +} + +namespace R::system_overlay_invalid::string { + constexpr ResourceId not_overlayable = 0x7f010000; + constexpr ResourceId other = 0x7f010001; + constexpr ResourceId policy_actor = 0x7f010002; + constexpr ResourceId policy_odm = 0x7f010003; + constexpr ResourceId policy_oem = 0x7f010004; + constexpr ResourceId policy_product = 0x7f010005; + constexpr ResourceId policy_public = 0x7f010006; + constexpr ResourceId policy_signature = 0x7f010007; + constexpr ResourceId policy_system = 0x7f010008; + constexpr ResourceId policy_system_vendor = 0x7f010009; +}; +// clang-format on + +} // namespace android::idmap2 + +#endif // IDMAP2_TESTS_R_H diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index b22fdafb09bb..5c5c81edee90 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -20,14 +20,20 @@ #include <sstream> #include <string> +#include "TestConstants.h" #include "TestHelpers.h" +#include "android-base/stringprintf.h" +#include "androidfw/ResourceTypes.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "idmap2/Idmap.h" #include "idmap2/RawPrintVisitor.h" +using android::base::StringPrintf; using ::testing::NotNull; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace android::idmap2 { #define ASSERT_CONTAINS_REGEX(pattern, str) \ @@ -48,7 +54,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); ASSERT_THAT(overlay_apk, NotNull()); - const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + const auto idmap = Idmap::FromApkAssets(*target_apk, *overlay_apk, PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_TRUE(idmap); @@ -59,8 +65,12 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { #define ADDRESS "[0-9a-f]{8}: " ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "00000003 version\n", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "76a20829 target crc\n", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "c054fb26 overlay crc\n", stream.str()); + ASSERT_CONTAINS_REGEX( + StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING), + stream.str()); + ASSERT_CONTAINS_REGEX( + StringPrintf(ADDRESS "%s overlay crc\n", android::idmap2::TestConstants::OVERLAY_CRC_STRING), + stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "00000004 target entry count\n", stream.str()); diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 39c4937b0930..de039f440e33 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -22,7 +22,9 @@ #include <utility> #include <vector> +#include "R.h" #include "TestHelpers.h" +#include "androidfw/ResourceTypes.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "idmap2/LogInfo.h" @@ -31,6 +33,8 @@ using android::Res_value; using android::idmap2::utils::ExtractOverlayManifestInfo; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace android::idmap2 { #define ASSERT_RESULT(r) \ @@ -106,20 +110,20 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsLegacy) { info.target_name = "TestResources"; info.resource_mapping = 0U; // no xml auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info, - PolicyFlags::POLICY_PUBLIC, + PolicyFlags::PUBLIC, /* enforce_overlayable */ false); ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U); - ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000, - false /* rewrite */)); // integer/int1 - ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000, - false /* rewrite */)); // string/str1 - ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001, - false /* rewrite */)); // string/str3 - ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002, - false /* rewrite */)); // string/str4 + ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_REFERENCE, + R::overlay::integer::int1, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, + R::overlay::string::str1, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_REFERENCE, + R::overlay::string::str3, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_REFERENCE, + R::overlay::string::str4, false /* rewrite */)); } TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) { @@ -128,18 +132,18 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNonMatchingNames) { info.target_name = "TestResources"; info.resource_mapping = 0x7f030003; // xml/overlays_swap auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info, - PolicyFlags::POLICY_PUBLIC, + PolicyFlags::PUBLIC, /* enforce_overlayable */ false); ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U); - ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020002, - true /* rewrite */)); // string/str1 -> string/str4 - ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020000, - true /* rewrite */)); // string/str3 -> string/str1 - ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001, - true /* rewrite */)); // string/str4 -> string/str3 + ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay::string::str4, true /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay::string::str1, true /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay::string::str3, true /* rewrite */)); } TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) { @@ -148,17 +152,17 @@ TEST(ResourceMappingTests, DoNotRewriteNonOverlayResourceId) { info.target_name = "TestResources"; info.resource_mapping = 0x7f030001; // xml/overlays_different_packages auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info, - PolicyFlags::POLICY_PUBLIC, + PolicyFlags::PUBLIC, /* enforce_overlayable */ false); ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U); ASSERT_EQ(res.GetOverlayToTargetMap().size(), 1U); - ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x0104000a, - false /* rewrite */)); // string/str1 -> android:string/ok - ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x7f020001, - true /* rewrite */)); // string/str3 -> string/str4 + ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x0104000a, + false /* rewrite */)); // -> android:string/ok + ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE, + 0x7f020001, true /* rewrite */)); } TEST(ResourceMappingTests, InlineResources) { @@ -167,7 +171,7 @@ TEST(ResourceMappingTests, InlineResources) { info.target_name = "TestResources"; info.resource_mapping = 0x7f030002; // xml/overlays_inline auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay.apk", info, - PolicyFlags::POLICY_PUBLIC, + PolicyFlags::PUBLIC, /* enforce_overlayable */ false); constexpr size_t overlay_string_pool_size = 8U; @@ -175,108 +179,120 @@ TEST(ResourceMappingTests, InlineResources) { auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U); ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U); - ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_STRING, + ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_STRING, overlay_string_pool_size + 0U, - false /* rewrite */)); // string/str1 -> "Hello World" - ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_INT_DEC, 73U, - false /* rewrite */)); // string/str1 -> "Hello World" + false /* rewrite */)); // -> "Hello World" + ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 73U, + false /* rewrite */)); // -> 73 } TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublic) { auto resources = TestGetResourceMapping("/target/target.apk", "/system-overlay/system-overlay.apk", - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, + PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC, /* enforce_overlayable */ true); ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U); - ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010000, - false /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010001, - false /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010002, - false /* rewrite */)); // string/policy_system_vendor + ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, + R::system_overlay::string::policy_public, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE, + R::system_overlay::string::policy_system, false /* rewrite */)); + ASSERT_RESULT( + MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE, + R::system_overlay::string::policy_system_vendor, false /* rewrite */)); } // Resources that are not declared as overlayable and resources that a protected by policies the // overlay does not fulfill must not map to overlay resources. TEST(ResourceMappingTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) { - auto resources = TestGetResourceMapping( - "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk", - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ true); + auto resources = TestGetResourceMapping("/target/target.apk", + "/system-overlay-invalid/system-overlay-invalid.apk", + PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC, + /* enforce_overlayable */ true); ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 3U); - ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005, - false /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007, - false /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008, - false /* rewrite */)); // string/policy_system_vendor + ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_public, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system, + false /* rewrite */)); + ASSERT_RESULT( + MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */)); } // Resources that are not declared as overlayable and resources that a protected by policies the // overlay does not fulfilled can map to overlay resources when overlayable enforcement is turned // off. TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) { - auto resources = TestGetResourceMapping( - "/target/target.apk", "/system-overlay-invalid/system-overlay-invalid.apk", - PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ false); + auto resources = TestGetResourceMapping("/target/target.apk", + "/system-overlay-invalid/system-overlay-invalid.apk", + PolicyFlags::SYSTEM_PARTITION | PolicyFlags::PUBLIC, + /* enforce_overlayable */ false); ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(res.GetTargetToOverlayMap().size(), 9U); - ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000, - false /* rewrite */)); // string/not_overlayable - ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001, - false /* rewrite */)); // string/other - ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002, - false /* rewrite */)); // string/policy_odm - ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003, - false /* rewrite */)); // string/policy_oem - ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004, - false /* rewrite */)); // string/policy_product - ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005, - false /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006, - false /* rewrite */)); // string/policy_signature - ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007, - false /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008, - false /* rewrite */)); // string/policy_system_vendor + ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U); + ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::not_overlayable, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::other, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_actor, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_odm, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_oem, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_product, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_public, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_signature, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system, + false /* rewrite */)); + ASSERT_RESULT( + MappingExists(res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */)); } // Overlays that do not target an <overlayable> tag can overlay resources defined within any // <overlayable> tag. TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTargetName) { auto resources = TestGetResourceMapping("/target/target.apk", "/overlay/overlay-no-name.apk", - PolicyFlags::POLICY_PUBLIC, + PolicyFlags::PUBLIC, /* enforce_overlayable */ false); ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U); - ASSERT_RESULT(MappingExists(res, 0x7f010000, Res_value::TYPE_REFERENCE, 0x7f010000, - false /* rewrite */)); // integer/int1 - ASSERT_RESULT(MappingExists(res, 0x7f02000c, Res_value::TYPE_REFERENCE, 0x7f020000, - false /* rewrite */)); // string/str1 - ASSERT_RESULT(MappingExists(res, 0x7f02000e, Res_value::TYPE_REFERENCE, 0x7f020001, - false /* rewrite */)); // string/str3 - ASSERT_RESULT(MappingExists(res, 0x7f02000f, Res_value::TYPE_REFERENCE, 0x7f020002, - false /* rewrite */)); // string/str4 + ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_REFERENCE, + R::overlay::integer::int1, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, + R::overlay::string::str1, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str3, Res_value::TYPE_REFERENCE, + R::overlay::string::str3, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::str4, Res_value::TYPE_REFERENCE, + R::overlay::string::str4, false /* rewrite */)); } // Overlays that are neither pre-installed nor signed with the same signature as the target cannot // overlay packages that have not defined overlayable resources. TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) { - auto resources = - TestGetResourceMapping("/target/target-no-overlayable.apk", "/overlay/overlay-no-name.apk", - PolicyFlags::POLICY_PUBLIC, - /* enforce_overlayable */ true); + auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk", + "/overlay/overlay-no-name.apk", PolicyFlags::PUBLIC, + /* enforce_overlayable */ true); ASSERT_TRUE(resources) << resources.GetErrorMessage(); ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U); @@ -293,33 +309,44 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 9U); - ASSERT_RESULT(MappingExists(res, 0x7f020003, Res_value::TYPE_REFERENCE, 0x7f010000, - false /* rewrite */)); // string/not_overlayable - ASSERT_RESULT(MappingExists(res, 0x7f020004, Res_value::TYPE_REFERENCE, 0x7f010001, - false /* rewrite */)); // string/other - ASSERT_RESULT(MappingExists(res, 0x7f020005, Res_value::TYPE_REFERENCE, 0x7f010002, - false /* rewrite */)); // string/policy_odm - ASSERT_RESULT(MappingExists(res, 0x7f020006, Res_value::TYPE_REFERENCE, 0x7f010003, - false /* rewrite */)); // string/policy_oem - ASSERT_RESULT(MappingExists(res, 0x7f020007, Res_value::TYPE_REFERENCE, 0x7f010004, - false /* rewrite */)); // string/policy_product - ASSERT_RESULT(MappingExists(res, 0x7f020008, Res_value::TYPE_REFERENCE, 0x7f010005, - false /* rewrite */)); // string/policy_public - ASSERT_RESULT(MappingExists(res, 0x7f020009, Res_value::TYPE_REFERENCE, 0x7f010006, - false /* rewrite */)); // string/policy_signature - ASSERT_RESULT(MappingExists(res, 0x7f02000a, Res_value::TYPE_REFERENCE, 0x7f010007, - false /* rewrite */)); // string/policy_system - ASSERT_RESULT(MappingExists(res, 0x7f02000b, Res_value::TYPE_REFERENCE, 0x7f010008, - false /* rewrite */)); // string/policy_system_vendor + ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U); + ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::not_overlayable, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::other, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_actor, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_odm, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_oem, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_product, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_public, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_signature, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system, + false /* rewrite */)); + ASSERT_RESULT(MappingExists( + res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */)); }; - CheckEntries(PolicyFlags::POLICY_SIGNATURE); - CheckEntries(PolicyFlags::POLICY_PRODUCT_PARTITION); - CheckEntries(PolicyFlags::POLICY_SYSTEM_PARTITION); - CheckEntries(PolicyFlags::POLICY_VENDOR_PARTITION); - CheckEntries(PolicyFlags::POLICY_ODM_PARTITION); - CheckEntries(PolicyFlags::POLICY_OEM_PARTITION); + CheckEntries(PolicyFlags::SIGNATURE); + CheckEntries(PolicyFlags::PRODUCT_PARTITION); + CheckEntries(PolicyFlags::SYSTEM_PARTITION); + CheckEntries(PolicyFlags::VENDOR_PARTITION); + CheckEntries(PolicyFlags::ODM_PARTITION); + CheckEntries(PolicyFlags::OEM_PARTITION); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h new file mode 100644 index 000000000000..6bc924e5ac3c --- /dev/null +++ b/cmds/idmap2/tests/TestConstants.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#ifndef IDMAP2_TESTS_TESTCONSTANTS_H +#define IDMAP2_TESTS_TESTCONSTANTS_H + +namespace android::idmap2::TestConstants { + +constexpr const auto TARGET_CRC = 0x41c60c8c; +constexpr const auto TARGET_CRC_STRING = "41c60c8c"; + +constexpr const auto OVERLAY_CRC = 0xc054fb26; +constexpr const auto OVERLAY_CRC_STRING = "c054fb26"; + +} // namespace android::idmap2::TestConstants + +#endif // IDMAP2_TESTS_TESTCONSTANTS_H diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml index 9ebfae41e4c5..7119d8283061 100644 --- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml +++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml @@ -25,6 +25,7 @@ <string name="policy_signature">policy_signature</string> <string name="policy_odm">policy_odm</string> <string name="policy_oem">policy_oem</string> + <string name="policy_actor">policy_actor</string> <!-- Requests to overlay a resource that is not declared as overlayable. --> <string name="not_overlayable">not_overlayable</string> diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk Binary files differindex 1456e749e796..bd990983693c 100644 --- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk +++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml index 8389f5635e15..ad4cd4882632 100644 --- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml +++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml @@ -41,6 +41,10 @@ <item type="string" name="policy_oem" /> </policy> + <policy type="actor"> + <item type="string" name="policy_actor" /> + </policy> + <!-- Resources publicly overlayable --> <policy type="public"> <item type="string" name="policy_public" /> @@ -63,4 +67,4 @@ <item type="string" name="other" /> </policy> </overlayable> -</resources>
\ No newline at end of file +</resources> diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml index a892c98f0fbb..5230e25e626b 100644 --- a/cmds/idmap2/tests/data/target/res/values/values.xml +++ b/cmds/idmap2/tests/data/target/res/values/values.xml @@ -36,6 +36,7 @@ <string name="policy_signature">policy_signature</string> <string name="policy_system">policy_system</string> <string name="policy_system_vendor">policy_system_vendor</string> + <string name="policy_actor">policy_actor</string> <string name="other">other</string> </resources> diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk Binary files differindex 2eb7c477c3b4..58504a74a83a 100644 --- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk +++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk Binary files differindex 251cf46f969d..c80e5eb65ff2 100644 --- a/cmds/idmap2/tests/data/target/target.apk +++ b/cmds/idmap2/tests/data/target/target.apk diff --git a/cmds/incident_helper/src/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp index 77a56e55045b..9439e1d44291 100644 --- a/cmds/incident_helper/src/ih_util.cpp +++ b/cmds/incident_helper/src/ih_util.cpp @@ -237,33 +237,38 @@ double toDouble(const std::string& s) { Reader::Reader(const int fd) { mFile = fdopen(fd, "r"); + mBuffer = new char[1024]; mStatus = mFile == nullptr ? "Invalid fd " + std::to_string(fd) : ""; } Reader::~Reader() { if (mFile != nullptr) fclose(mFile); + free(mBuffer); } bool Reader::readLine(std::string* line) { if (mFile == nullptr) return false; - char* buf = nullptr; size_t len = 0; - ssize_t read = getline(&buf, &len, mFile); + ssize_t read = getline(&mBuffer, &len, mFile); if (read != -1) { - std::string s(buf); + std::string s(mBuffer); line->assign(trim(s, DEFAULT_NEWLINE)); - } else if (errno == EINVAL) { - mStatus = "Bad Argument"; + return true; } - free(buf); - return read != -1; + if (!feof(mFile)) { + mStatus = "Error reading file. Ferror: " + std::to_string(ferror(mFile)); + } + return false; } bool Reader::ok(std::string* error) { + if (mStatus.empty()) { + return true; + } error->assign(mStatus); - return mStatus.empty(); + return false; } // ============================================================================== diff --git a/cmds/incident_helper/src/ih_util.h b/cmds/incident_helper/src/ih_util.h index 09dc8e6fdbfc..5812c603297e 100644 --- a/cmds/incident_helper/src/ih_util.h +++ b/cmds/incident_helper/src/ih_util.h @@ -117,6 +117,7 @@ public: private: FILE* mFile; + char* mBuffer; std::string mStatus; }; diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 73a8f666b78e..0c3a49a9d340 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -302,11 +302,7 @@ cc_test { static_libs: [ "libgmock", "libplatformprotos", - - // TODO(b/149842105): Make libstatssocket shared and remove libcutils once statsd_test is - // moved to the apex. - "libstatssocket", - "libcutils", + "libstatssocket_private", ], proto: { diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 257554207ef5..e58e7bc11315 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -380,8 +380,8 @@ message Atom { BootTimeEventErrorCode boot_time_event_error_code_reported = 242 [(module) = "framework"]; UserspaceRebootReported userspace_reboot_reported = 243 [(module) = "framework"]; NotificationReported notification_reported = 244 [(module) = "framework"]; - NotificationPanelReported notification_panel_reported = 245; - NotificationChannelModified notification_channel_modified = 246; + NotificationPanelReported notification_panel_reported = 245 [(module) = "sysui"]; + NotificationChannelModified notification_channel_modified = 246 [(module) = "framework"]; IntegrityCheckResultReported integrity_check_result_reported = 247 [(module) = "framework"]; IntegrityRulesPushed integrity_rules_pushed = 248 [(module) = "framework"]; CellBroadcastMessageReported cb_message_reported = @@ -393,6 +393,10 @@ message Atom { WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"]; AppFreezeChanged app_freeze_changed = 254 [(module) = "framework"]; SnapshotMergeReported snapshot_merge_reported = 255; + ForegroundServiceAppOpSessionEnded foreground_service_app_op_session_ended = + 256 [(module) = "framework"]; + DisplayJankReported display_jank_reported = 257; + AppStandbyBucketChanged app_standby_bucket_changed = 258 [(module) = "framework"]; SdkExtensionStatus sdk_extension_status = 354; } @@ -978,6 +982,17 @@ message ScheduledJobStateChanged { // The job id (as assigned by the app). optional int32 job_id = 6; + + // One flag for each of the API constraints defined by Jobscheduler. Does not include implcit + // constraints as they are always assumed to be set. + optional bool has_charging_constraint = 7; + optional bool has_battery_not_low_constraint = 8; + optional bool has_storage_not_low_constraint = 9; + optional bool has_timing_delay_constraint = 10; + optional bool has_deadline_constraint = 11; + optional bool has_idle_constraint = 12; + optional bool has_connectivity_constraint = 13; + optional bool has_content_trigger_constraint = 14; } /** @@ -1213,18 +1228,8 @@ message WakeupAlarmOccurred { // Name of source package (for historical reasons, since BatteryStats tracked it). optional string package_name = 3; - // These enum values match the STANDBY_BUCKET_XXX constants defined in UsageStatsManager.java. - enum Bucket { - UNKNOWN = 0; - EXEMPTED = 5; - ACTIVE = 10; - WORKING_SET = 20; - FREQUENT = 30; - RARE = 40; - NEVER = 50; - } // The App Standby bucket of the app that scheduled the alarm at the time the alarm fired. - optional Bucket app_standby_bucket = 4; + optional AppStandbyBucketChanged.Bucket app_standby_bucket = 4; } /** @@ -3285,12 +3290,12 @@ message OverlayStateChanged { ]; } -/* +/** * Logs foreground service starts and stops. * Note that this is not when a service starts or stops, but when it is * considered foreground. * Logged from - * //frameworks/base/services/core/java/com/android/server/am/ActiveServices.java + * frameworks/base/services/core/java/com/android/server/am/ActiveServices.java */ message ForegroundServiceStateChanged { optional int32 uid = 1 [(is_uid) = true]; @@ -3302,6 +3307,49 @@ message ForegroundServiceStateChanged { EXIT = 2; } optional State state = 3; + + // Whether the fgs is allowed while-in-use permissions, i.e. is considered 'in-use' to the user. + // (If the fgs was started while the app wasn't TOP it usually will be denied these permissions) + optional bool allow_while_in_use_permission = 4; +} + +/** + * Logs the number of times a uid accesses a sensitive AppOp during a foreground service session. + * A foreground service session is any continuous period during which the uid holds at least one + * foreground service; the atom will be pushed when the uid no longer holds any foreground services. + * Accesses initiated while the uid is in the TOP state are ignored. + * Sessions with no attempted accesses are not logged. + * Logged from + * frameworks/base/services/core/java/com/android/server/am/ActiveServices.java + */ +message ForegroundServiceAppOpSessionEnded { + optional int32 uid = 1 [(is_uid) = true]; + + // The operation's name. + // To the extent possible, preserve the mapping from AppOpsManager.OP_ constants. + // Only these named ops are actually logged. + enum AppOpName { + OP_NONE = -1; // Also represents UNKNOWN. + OP_COARSE_LOCATION = 0; + OP_FINE_LOCATION = 1; + OP_CAMERA = 26; + OP_RECORD_AUDIO = 27; + } + optional AppOpName app_op_name = 2 [default = OP_NONE]; + + // The uid's permission mode for accessing the AppOp during this fgs session. + enum Mode { + MODE_UNKNOWN = 0; + MODE_ALLOWED = 1; // Always allowed + MODE_IGNORED = 2; // Denied + MODE_FOREGROUND = 3; // Allow-while-in-use (or allowed-one-time) + } + optional Mode app_op_mode = 3; + + // Number of times this AppOp was requested and allowed. + optional int32 count_ops_accepted = 4; + // Number of times this AppOp was requested but denied. + optional int32 count_ops_rejected = 5; } /** @@ -3589,8 +3637,8 @@ message NotificationChannelModified { // The notifying app's uid and package. optional int32 uid = 2 [(is_uid) = true]; optional string package_name = 3; - // App-assigned notification channel ID or channel-group ID - optional string channel_id = 4; + // Hash of app-assigned notification channel ID or channel-group ID + optional int32 channel_id_hash = 4; // Previous importance setting, if applicable optional android.stats.sysui.NotificationImportance old_importance = 5; // New importance setting @@ -8183,13 +8231,29 @@ message FrameTimingHistogram { } /** + * Janky event as reported by SurfaceFlinger. + * This event is intended to be consumed by a Perfetto subscriber for + * automated trace collection. + * + * Logged from: + * frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp + */ +message DisplayJankReported { + // Informational field for how long the janky event lasted in milliseconds + optional int64 event_duration_millis = 1; + // Number of frame deadlines missed, where SurfaceFlinger failed to update + // the display on time. + optional int32 present_deadlines_missed = 2; +} + +/** * Information about camera facing and API level usage. * Logged from: * frameworks/base/services/core/java/com/android/server/camera/CameraServiceProxy.java */ message CameraActionEvent { // Camera session duration - optional int64 duration = 1; + optional int64 duration_millis = 1; // Camera API level used optional int32 api_level = 2; @@ -8651,3 +8715,45 @@ message GnssStats { // Total number of L5 sv status messages reports, where sv is used in fix since boot optional int64 l5_sv_status_reports_used_in_fix = 14; } + +/** + * Logs when an app is moved to a different standby bucket. + * + * Logged from: + * frameworks/base/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java + */ +message AppStandbyBucketChanged { + optional string package_name = 1; + + // Should be 0, 10, 11, 12, etc. where 0 is the owner. See UserHandle for more documentation. + optional int32 user_id = 2; + + // These enum values match the constants defined in UsageStatsManager.java. + enum Bucket { + BUCKET_UNKNOWN = 0; + BUCKET_EXEMPTED = 5; + BUCKET_ACTIVE = 10; + BUCKET_WORKING_SET = 20; + BUCKET_FREQUENT = 30; + BUCKET_RARE = 40; + BUCKET_RESTRICTED = 45; + BUCKET_NEVER = 50; + } + optional Bucket bucket = 3; + + enum MainReason { + MAIN_UNKNOWN = 0; + MAIN_DEFAULT = 0x0100; + MAIN_TIMEOUT = 0x0200; + MAIN_USAGE = 0x0300; + MAIN_FORCED_BY_USER = 0x0400; + MAIN_PREDICTED = 0x0500; + MAIN_FORCED_BY_SYSTEM = 0x0600; + } + optional MainReason main_reason = 4; + + // A more detailed reason for the standby bucket change. The sub reason name is dependent on + // the main reason. Values are one of the REASON_SUB_XXX constants defined in + // UsageStatsManager.java. + optional int32 sub_reason = 5; +} diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp index 0edf40b69087..933f48d1714b 100644 --- a/cmds/statsd/src/external/StatsCallbackPuller.cpp +++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp @@ -66,10 +66,8 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { { lock_guard<mutex> lk(*cv_mutex); for (const StatsEventParcel& parcel: output) { - uint8_t* buf = reinterpret_cast<uint8_t*>( - const_cast<int8_t*>(parcel.buffer.data())); - shared_ptr<LogEvent> event = make_shared<LogEvent>( - buf, parcel.buffer.size(), /*uid=*/-1, /*pid=*/-1); + shared_ptr<LogEvent> event = make_shared<LogEvent>(/*uid=*/-1, /*pid=*/-1); + event->parseBuffer((uint8_t*)parcel.buffer.data(), parcel.buffer.size()); sharedData->push_back(event); } *pullSuccess = success; diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 3e46d131a813..974e203cd612 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -65,18 +65,6 @@ using std::vector; #define ATTRIBUTION_CHAIN_TYPE 0x09 #define ERROR_TYPE 0x0F -// Msg is expected to begin at the start of the serialized atom -- it should not -// include the android_log_header_t or the StatsEventTag. -LogEvent::LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid) - : mBuf(msg), - mRemainingLen(len), - mLogdTimestampNs(time(nullptr)), - mLogUid(uid), - mLogPid(pid) -{ - initNew(); -} - LogEvent::LogEvent(const LogEvent& event) { mTagId = event.mTagId; mLogUid = event.mLogUid; @@ -86,6 +74,12 @@ LogEvent::LogEvent(const LogEvent& event) { mValues = event.mValues; } +LogEvent::LogEvent(int32_t uid, int32_t pid) + : mLogdTimestampNs(time(nullptr)), + mLogUid(uid), + mLogPid(pid) { +} + LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) { mLogdTimestampNs = wallClockTimestampNs; mElapsedTimestampNs = elapsedTimestampNs; @@ -189,9 +183,6 @@ LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status))); } -LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, timestampNs) { -} - LogEvent::LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid) { mLogdTimestampNs = timestampNs; mTagId = tagId; @@ -467,7 +458,10 @@ void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last) { // This parsing logic is tied to the encoding scheme used in StatsEvent.java and // stats_event.c -void LogEvent::initNew() { +bool LogEvent::parseBuffer(uint8_t* buf, size_t len) { + mBuf = buf; + mRemainingLen = (uint32_t)len; + int32_t pos[] = {1, 1, 1}; bool last[] = {false, false, false}; @@ -529,6 +523,7 @@ void LogEvent::initNew() { if (mRemainingLen != 0) mValid = false; mBuf = nullptr; + return mValid; } uint8_t LogEvent::getTypeId(uint8_t typeInfo) { diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index e167e6721d01..3940aa8e1243 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -20,7 +20,6 @@ #include <android/util/ProtoOutputStream.h> #include <private/android_logger.h> -#include <stats_event.h> #include <string> #include <vector> @@ -61,14 +60,32 @@ struct InstallTrainInfo { }; /** - * Wrapper for the log_msg structure. + * This class decodes the structured, serialized encoding of an atom into a + * vector of FieldValues. */ class LogEvent { public: /** - * Read a LogEvent from the socket + * \param uid user id of the logging caller + * \param pid process id of the logging caller */ - explicit LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid); + explicit LogEvent(int32_t uid, int32_t pid); + + /** + * Parses the atomId, timestamp, and vector of values from a buffer + * containing the StatsEvent/AStatsEvent encoding of an atom. + * + * \param buf a buffer that begins at the start of the serialized atom (it + * should not include the android_log_header_t or the StatsEventTag) + * \param len size of the buffer + * + * \return success of the initialization + */ + bool parseBuffer(uint8_t* buf, size_t len); + + // TODO(b/149590301): delete unused functions below once LogEvent uses the + // new socket schema within test code. Really we would like the only entry + // points into LogEvent to be the above constructor and parseBuffer functions. /** * Constructs a LogEvent with synthetic data for testing. Must call init() before reading. @@ -76,9 +93,6 @@ public: explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs); // For testing. The timestamp is used as both elapsed real time and logd timestamp. - explicit LogEvent(int32_t tagId, int64_t timestampNs); - - // For testing. The timestamp is used as both elapsed real time and logd timestamp. explicit LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid); /** @@ -192,10 +206,6 @@ public: return &mValues; } - bool isValid() { - return mValid; - } - inline LogEvent makeCopy() { return LogEvent(*this); } @@ -222,12 +232,6 @@ private: */ LogEvent(const LogEvent&); - - /** - * Parsing function for new encoding scheme. - */ - void initNew(); - void parseInt32(int32_t* pos, int32_t depth, bool* last); void parseInt64(int32_t* pos, int32_t depth, bool* last); void parseString(int32_t* pos, int32_t depth, bool* last); @@ -238,13 +242,14 @@ private: void parseAttributionChain(int32_t* pos, int32_t depth, bool* last); /** - * mBuf is a pointer to the current location in the buffer being parsed. - * Because the buffer lives on the StatsSocketListener stack, this pointer - * is only valid during the LogEvent constructor. It will be set to null at - * the end of initNew. + * The below three variables are only valid during the execution of + * parseBuffer. There are no guarantees about the state of these variables + * before/after. + * + * TODO (b/150312423): These shouldn't be member variables. We should pass + * them around as parameters. */ uint8_t* mBuf; - uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed bool mValid = true; // stores whether the event we received from the socket is valid diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp index 8f0f480cb862..b877cc9c352f 100755 --- a/cmds/statsd/src/socket/StatsSocketListener.cpp +++ b/cmds/statsd/src/socket/StatsSocketListener.cpp @@ -126,7 +126,10 @@ bool StatsSocketListener::onDataAvailable(SocketClient* cli) { uint32_t pid = cred->pid; int64_t oldestTimestamp; - if (!mQueue->push(std::make_unique<LogEvent>(msg, len, uid, pid), &oldestTimestamp)) { + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(uid, pid); + logEvent->parseBuffer(msg, len); + + if (!mQueue->push(std::move(logEvent), &oldestTimestamp)) { StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp); } diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 7542faf25123..7458cbf9e9a1 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -54,8 +54,9 @@ TEST(LogEventTest, TestPrimitiveParsing) { size_t size; uint8_t* buf = AStatsEvent_getBuffer(event, &size); - LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001); - EXPECT_TRUE(logEvent.isValid()); + LogEvent logEvent(/*uid=*/1000, /*pid=*/1001); + EXPECT_TRUE(logEvent.parseBuffer(buf, size)); + EXPECT_EQ(100, logEvent.GetTagId()); EXPECT_EQ(1000, logEvent.GetUid()); EXPECT_EQ(1001, logEvent.GetPid()); @@ -102,8 +103,9 @@ TEST(LogEventTest, TestStringAndByteArrayParsing) { size_t size; uint8_t* buf = AStatsEvent_getBuffer(event, &size); - LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001); - EXPECT_TRUE(logEvent.isValid()); + LogEvent logEvent(/*uid=*/ 1000, /*pid=*/ 1001); + EXPECT_TRUE(logEvent.parseBuffer(buf, size)); + EXPECT_EQ(100, logEvent.GetTagId()); EXPECT_EQ(1000, logEvent.GetUid()); EXPECT_EQ(1001, logEvent.GetPid()); @@ -137,8 +139,9 @@ TEST(LogEventTest, TestEmptyString) { size_t size; uint8_t* buf = AStatsEvent_getBuffer(event, &size); - LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001); - EXPECT_TRUE(logEvent.isValid()); + LogEvent logEvent(/*uid=*/ 1000, /*pid=*/ 1001); + EXPECT_TRUE(logEvent.parseBuffer(buf, size)); + EXPECT_EQ(100, logEvent.GetTagId()); EXPECT_EQ(1000, logEvent.GetUid()); EXPECT_EQ(1001, logEvent.GetPid()); @@ -165,8 +168,9 @@ TEST(LogEventTest, TestByteArrayWithNullCharacter) { size_t size; uint8_t* buf = AStatsEvent_getBuffer(event, &size); - LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001); - EXPECT_TRUE(logEvent.isValid()); + LogEvent logEvent(/*uid=*/ 1000, /*pid=*/ 1001); + EXPECT_TRUE(logEvent.parseBuffer(buf, size)); + EXPECT_EQ(100, logEvent.GetTagId()); EXPECT_EQ(1000, logEvent.GetUid()); EXPECT_EQ(1001, logEvent.GetPid()); @@ -200,8 +204,9 @@ TEST(LogEventTest, TestAttributionChain) { size_t size; uint8_t* buf = AStatsEvent_getBuffer(event, &size); - LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001); - EXPECT_TRUE(logEvent.isValid()); + LogEvent logEvent(/*uid=*/ 1000, /*pid=*/ 1001); + EXPECT_TRUE(logEvent.parseBuffer(buf, size)); + EXPECT_EQ(100, logEvent.GetTagId()); EXPECT_EQ(1000, logEvent.GetUid()); EXPECT_EQ(1001, logEvent.GetPid()); diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp index 36094b217303..4b78e305f65c 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include "src/condition/SimpleConditionTracker.h" +#include "stats_event.h" #include "tests/statsd_test_util.h" #include <gmock/gmock.h> @@ -31,6 +32,8 @@ namespace android { namespace os { namespace statsd { +namespace { + const ConfigKey kConfigKey(0, 12345); const int ATTRIBUTION_NODE_FIELD_ID = 1; @@ -57,24 +60,33 @@ SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse, return simplePredicate; } -void writeAttributionNodesToEvent(LogEvent* event, const std::vector<int> &uids) { - std::vector<AttributionNodeInternal> nodes; - for (size_t i = 0; i < uids.size(); ++i) { - AttributionNodeInternal node; - node.set_uid(uids[i]); - nodes.push_back(node); +void makeWakeLockEvent(LogEvent* logEvent, uint32_t atomId, uint64_t timestamp, + const vector<int>& uids, const string& wl, int acquire) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, atomId); + AStatsEvent_overwriteTimestamp(statsEvent, timestamp); + + vector<std::string> tags(uids.size()); // vector of empty strings + vector<const char*> cTags(uids.size()); + for (int i = 0; i < cTags.size(); i++) { + cTags[i] = tags[i].c_str(); } - event->write(nodes); // attribution chain. + AStatsEvent_writeAttributionChain(statsEvent, reinterpret_cast<const uint32_t*>(uids.data()), + cTags.data(), uids.size()); + + AStatsEvent_writeString(statsEvent, wl.c_str()); + AStatsEvent_writeInt32(statsEvent, acquire); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + logEvent->parseBuffer(buf, size); + + AStatsEvent_release(statsEvent); } -// TODO(b/149590301): Update this helper to use new socket schema. -//void makeWakeLockEvent( -// LogEvent* event, const std::vector<int> &uids, const string& wl, int acquire) { -// writeAttributionNodesToEvent(event, uids); -// event->write(wl); -// event->write(acquire); -// event->init(); -//} +} // anonymous namespace + std::map<int64_t, HashableDimensionKey> getWakeLockQueryKey( const Position position, @@ -265,138 +277,128 @@ TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) { EXPECT_TRUE(changedCache[0]); } -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(SimpleConditionTrackerTest, TestSlicedCondition) { -// std::vector<sp<ConditionTracker>> allConditions; -// for (Position position : -// { Position::FIRST, Position::LAST}) { -// -// SimplePredicate simplePredicate = getWakeLockHeldCondition( -// true /*nesting*/, true /*default to false*/, true /*output slice by uid*/, -// position); -// string conditionName = "WL_HELD_BY_UID2"; -// -// unordered_map<int64_t, int> trackerNameIndexMap; -// trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0; -// trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; -// trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; -// -// SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), -// 0 /*condition tracker index*/, simplePredicate, -// trackerNameIndexMap); -// -// std::vector<int> uids = {111, 222, 333}; -// -// LogEvent event(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event, uids, "wl1", 1); -// -// // one matched start -// vector<MatchingState> matcherState; -// matcherState.push_back(MatchingState::kMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// vector<sp<ConditionTracker>> allPredicates; -// vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated); -// vector<bool> changedCache(1, false); -// -// conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache, -// changedCache); -// -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); -// } else { -// EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size()); -// } -// EXPECT_TRUE(changedCache[0]); -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u); -// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); -// } else { -// EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), uids.size()); -// } -// -// // Now test query -// const auto queryKey = getWakeLockQueryKey(position, uids, conditionName); -// conditionCache[0] = ConditionState::kNotEvaluated; -// -// conditionTracker.isConditionMet(queryKey, allPredicates, -// false, -// conditionCache); -// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); -// -// // another wake lock acquired by this uid -// LogEvent event2(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event2, uids, "wl2", 1); -// matcherState.clear(); -// matcherState.push_back(MatchingState::kMatched); -// matcherState.push_back(MatchingState::kNotMatched); -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache, -// changedCache); -// EXPECT_FALSE(changedCache[0]); -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); -// } else { -// EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size()); -// } -// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); -// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); -// -// -// // wake lock 1 release -// LogEvent event3(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event3, uids, "wl1", 0); // now release it. -// matcherState.clear(); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kMatched); -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache, -// changedCache); -// // nothing changes, because wake lock 2 is still held for this uid -// EXPECT_FALSE(changedCache[0]); -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); -// } else { -// EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size()); -// } -// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); -// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); -// -// LogEvent event4(1 /*tagId*/, 0 /*timestamp*/); -// makeWakeLockEvent(&event4, uids, "wl2", 0); // now release it. -// matcherState.clear(); -// matcherState.push_back(MatchingState::kNotMatched); -// matcherState.push_back(MatchingState::kMatched); -// conditionCache[0] = ConditionState::kNotEvaluated; -// changedCache[0] = false; -// conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache, -// changedCache); -// EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size()); -// EXPECT_TRUE(changedCache[0]); -// if (position == Position::FIRST || -// position == Position::LAST) { -// EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u); -// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); -// } else { -// EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), uids.size()); -// } -// -// // query again -// conditionCache[0] = ConditionState::kNotEvaluated; -// conditionTracker.isConditionMet(queryKey, allPredicates, -// false, -// conditionCache); -// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]); -// } -// -//} -// +TEST(SimpleConditionTrackerTest, TestSlicedCondition) { + std::vector<sp<ConditionTracker>> allConditions; + for (Position position : {Position::FIRST, Position::LAST}) { + SimplePredicate simplePredicate = getWakeLockHeldCondition( + true /*nesting*/, true /*default to false*/, true /*output slice by uid*/, + position); + string conditionName = "WL_HELD_BY_UID2"; + + unordered_map<int64_t, int> trackerNameIndexMap; + trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0; + trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1; + trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2; + + SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), + 0 /*condition tracker index*/, simplePredicate, + trackerNameIndexMap); + + std::vector<int> uids = {111, 222, 333}; + + LogEvent event(/*uid=*/-1, /*pid=*/-1); + makeWakeLockEvent(&event, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1); + + // one matched start + vector<MatchingState> matcherState; + matcherState.push_back(MatchingState::kMatched); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kNotMatched); + vector<sp<ConditionTracker>> allPredicates; + vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated); + vector<bool> changedCache(1, false); + + conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache, + changedCache); + + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); + } else { + EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size()); + } + EXPECT_TRUE(changedCache[0]); + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u); + EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); + } else { + EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), + uids.size()); + } + + // Now test query + const auto queryKey = getWakeLockQueryKey(position, uids, conditionName); + conditionCache[0] = ConditionState::kNotEvaluated; + + conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache); + EXPECT_EQ(ConditionState::kTrue, conditionCache[0]); + + // another wake lock acquired by this uid + LogEvent event2(/*uid=*/-1, /*pid=*/-1); + makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/1); + matcherState.clear(); + matcherState.push_back(MatchingState::kMatched); + matcherState.push_back(MatchingState::kNotMatched); + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache, + changedCache); + EXPECT_FALSE(changedCache[0]); + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); + } else { + EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size()); + } + EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); + EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); + + + // wake lock 1 release + LogEvent event3(/*uid=*/-1, /*pid=*/-1); + makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0); + matcherState.clear(); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kMatched); + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache, + changedCache); + // nothing changes, because wake lock 2 is still held for this uid + EXPECT_FALSE(changedCache[0]); + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size()); + } else { + EXPECT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size()); + } + EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); + EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty()); + + LogEvent event4(/*uid=*/-1, /*pid=*/-1); + makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0); + matcherState.clear(); + matcherState.push_back(MatchingState::kNotMatched); + matcherState.push_back(MatchingState::kMatched); + conditionCache[0] = ConditionState::kNotEvaluated; + changedCache[0] = false; + conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache, + changedCache); + EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size()); + EXPECT_TRUE(changedCache[0]); + if (position == Position::FIRST || position == Position::LAST) { + EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u); + EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty()); + } else { + EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), + uids.size()); + } + + // query again + conditionCache[0] = ConditionState::kNotEvaluated; + conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache); + EXPECT_EQ(ConditionState::kFalse, conditionCache[0]); + } + +} + //TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) { // std::vector<sp<ConditionTracker>> allConditions; // diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp index e416b4c0e29b..1ff66218f22c 100644 --- a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp +++ b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp @@ -28,6 +28,7 @@ #include "../metrics/metrics_test_helper.h" #include "src/stats_log_util.h" +#include "stats_event.h" #include "tests/statsd_test_util.h" #ifdef __ANDROID__ diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp index f27d12957f11..c4407f48d978 100644 --- a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp +++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp @@ -16,9 +16,11 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <stdio.h> + #include <thread> -#include <stdio.h> +#include "stats_event.h" namespace android { namespace os { @@ -29,6 +31,25 @@ using namespace testing; using std::unique_ptr; +namespace { + +std::unique_ptr<LogEvent> makeLogEvent(uint64_t timestampNs) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, 10); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + + std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/-1, /*pid=*/-1); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + return logEvent; +} + +} // anonymous namespace + #ifdef __ANDROID__ TEST(LogEventQueue_test, TestGoodConsumer) { LogEventQueue queue(50); @@ -36,8 +57,7 @@ TEST(LogEventQueue_test, TestGoodConsumer) { std::thread writer([&queue, timeBaseNs] { for (int i = 0; i < 100; i++) { int64_t oldestEventNs; - bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000), - &oldestEventNs); + bool success = queue.push(makeLogEvent(timeBaseNs + i * 1000), &oldestEventNs); EXPECT_TRUE(success); std::this_thread::sleep_for(std::chrono::milliseconds(1)); } @@ -63,8 +83,7 @@ TEST(LogEventQueue_test, TestSlowConsumer) { int failure_count = 0; int64_t oldestEventNs; for (int i = 0; i < 100; i++) { - bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000), - &oldestEventNs); + bool success = queue.push(makeLogEvent(timeBaseNs + i * 1000), &oldestEventNs); if (!success) failure_count++; std::this_thread::sleep_for(std::chrono::milliseconds(1)); } diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 2bfce9b07eb5..d416f1395727 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -15,6 +15,7 @@ #include "statsd_test_util.h" #include <aidl/android/util/StatsEventParcel.h> +#include "stats_event.h" using aidl::android::util::StatsEventParcel; using std::shared_ptr; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 3b0667d1e377..ca22bf4a62dc 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -16,6 +16,8 @@ package android.accessibilityservice; +import static android.accessibilityservice.util.AccessibilityUtils.getFilteredHtmlText; +import static android.accessibilityservice.util.AccessibilityUtils.loadSafeAnimatedImage; import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; import android.annotation.IntDef; @@ -27,7 +29,6 @@ import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; @@ -782,12 +783,10 @@ public class AccessibilityServiceInfo implements Parcelable { } /** - * The animated image resource id. - * <p> - * <strong>Statically set from - * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> - * </p> + * Gets the animated image resource id. + * * @return The animated image resource id. + * * @hide */ public int getAnimatedImageRes() { @@ -797,10 +796,14 @@ public class AccessibilityServiceInfo implements Parcelable { /** * The animated image drawable. * <p> + * Image can not exceed the screen size. * <strong>Statically set from * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> * </p> - * @return The animated image drawable. + * @return The animated image drawable, or null if the resource is invalid or the image + * exceed the screen size. + * + * @hide */ @Nullable public Drawable loadAnimatedImage(@NonNull Context context) { @@ -808,11 +811,8 @@ public class AccessibilityServiceInfo implements Parcelable { return null; } - final PackageManager packageManager = context.getPackageManager(); - final String packageName = mComponentName.getPackageName(); - final ApplicationInfo applicationInfo = mResolveInfo.serviceInfo.applicationInfo; - - return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo); + return loadSafeAnimatedImage(context, mResolveInfo.serviceInfo.applicationInfo, + mAnimatedImageRes); } /** @@ -924,16 +924,19 @@ public class AccessibilityServiceInfo implements Parcelable { } /** - * The localized html description of the accessibility service. + * The localized and restricted html description of the accessibility service. * <p> + * Filters the <img> tag which do not meet the custom specification and the <a> tag. * <strong>Statically set from * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> * </p> - * @return The localized html description. + * @return The localized and restricted html description. + * + * @hide */ @Nullable public String loadHtmlDescription(@NonNull PackageManager packageManager) { - if (mHtmlDescriptionRes == 0) { + if (mHtmlDescriptionRes == /* invalid */ 0) { return null; } @@ -941,7 +944,7 @@ public class AccessibilityServiceInfo implements Parcelable { final CharSequence htmlDescription = packageManager.getText(serviceInfo.packageName, mHtmlDescriptionRes, serviceInfo.applicationInfo); if (htmlDescription != null) { - return htmlDescription.toString().trim(); + return getFilteredHtmlText(htmlDescription.toString().trim()); } return null; } diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java index 62096792d764..d2bdf8051f74 100644 --- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java @@ -16,18 +16,21 @@ package android.accessibilityservice; +import static android.accessibilityservice.util.AccessibilityUtils.getFilteredHtmlText; +import static android.accessibilityservice.util.AccessibilityUtils.loadSafeAnimatedImage; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; 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.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Xml; @@ -134,7 +137,7 @@ public final class AccessibilityShortcutInfo { // Gets animated image mAnimatedImageRes = asAttributes.getResourceId( com.android.internal.R.styleable - .AccessibilityShortcutTarget_animatedImageDrawable, 0); + .AccessibilityShortcutTarget_animatedImageDrawable, /* defValue= */ 0); // Gets html description mHtmlDescriptionRes = asAttributes.getResourceId( com.android.internal.R.styleable.AccessibilityShortcutTarget_htmlDescription, @@ -192,7 +195,7 @@ public final class AccessibilityShortcutInfo { } /** - * The animated image resource id of the accessibility shortcut target. + * Gets the animated image resource id. * * @return The animated image resource id. * @@ -205,7 +208,10 @@ public final class AccessibilityShortcutInfo { /** * The animated image drawable of the accessibility shortcut target. * - * @return The animated image drawable. + * @return The animated image drawable, or null if the resource is invalid or the image + * exceed the screen size. + * + * @hide */ @Nullable public Drawable loadAnimatedImage(@NonNull Context context) { @@ -213,21 +219,22 @@ public final class AccessibilityShortcutInfo { return null; } - final PackageManager packageManager = context.getPackageManager(); - final String packageName = mComponentName.getPackageName(); - final ApplicationInfo applicationInfo = mActivityInfo.applicationInfo; - - return packageManager.getDrawable(packageName, mAnimatedImageRes, applicationInfo); + return loadSafeAnimatedImage(context, mActivityInfo.applicationInfo, mAnimatedImageRes); } /** - * The localized html description of the accessibility shortcut target. + * The localized and restricted html description of the accessibility shortcut target. + * It filters the <img> tag which do not meet the custom specification and the <a> tag. + * + * @return The localized and restricted html description. * - * @return The localized html description. + * @hide */ @Nullable public String loadHtmlDescription(@NonNull PackageManager packageManager) { - return loadResourceString(packageManager, mActivityInfo, mHtmlDescriptionRes); + final String htmlDescription = loadResourceString(packageManager, mActivityInfo, + mHtmlDescriptionRes); + return TextUtils.isEmpty(htmlDescription) ? null : getFilteredHtmlText(htmlDescription); } /** diff --git a/core/java/android/accessibilityservice/util/AccessibilityUtils.java b/core/java/android/accessibilityservice/util/AccessibilityUtils.java new file mode 100644 index 000000000000..fa32bb2ab978 --- /dev/null +++ b/core/java/android/accessibilityservice/util/AccessibilityUtils.java @@ -0,0 +1,139 @@ +/* + * 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.accessibilityservice.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StringRes; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Collection of utilities for accessibility service. + * + * @hide + */ +public final class AccessibilityUtils { + private AccessibilityUtils() {} + + // Used for html description of accessibility service. The <img> src tag must follow the + // prefix rule. e.g. <img src="R.drawable.fileName"/> + private static final String IMG_PREFIX = "R.drawable."; + private static final String ANCHOR_TAG = "a"; + private static final List<String> UNSUPPORTED_TAG_LIST = new ArrayList<>( + Collections.singletonList(ANCHOR_TAG)); + + /** + * Gets the filtered html string for + * {@link android.accessibilityservice.AccessibilityServiceInfo} and + * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It filters + * the <img> tag which do not meet the custom specification and the <a> tag. + * + * @param text the target text is html format. + * @return the filtered html string. + */ + public static @NonNull String getFilteredHtmlText(@NonNull String text) { + final String replacementStart = "<invalidtag "; + final String replacementEnd = "</invalidtag>"; + + for (String tag : UNSUPPORTED_TAG_LIST) { + final String regexStart = "(?i)<" + tag + "(\\s+|>)"; + final String regexEnd = "(?i)</" + tag + "\\s*>"; + text = Pattern.compile(regexStart).matcher(text).replaceAll(replacementStart); + text = Pattern.compile(regexEnd).matcher(text).replaceAll(replacementEnd); + } + + final String regexInvalidImgTag = "(?i)<img\\s+(?!src\\s*=\\s*\"(?-i)" + IMG_PREFIX + ")"; + text = Pattern.compile(regexInvalidImgTag).matcher(text).replaceAll( + replacementStart); + + return text; + } + + /** + * Loads the animated image for + * {@link android.accessibilityservice.AccessibilityServiceInfo} and + * {@link android.accessibilityservice.AccessibilityShortcutInfo}. It checks the resource + * whether to exceed the screen size. + * + * @param context the current context. + * @param applicationInfo the current application. + * @param resId the animated image resource id. + * @return the animated image which is safe. + */ + @Nullable + public static Drawable loadSafeAnimatedImage(@NonNull Context context, + @NonNull ApplicationInfo applicationInfo, @StringRes int resId) { + if (resId == /* invalid */ 0) { + return null; + } + + final PackageManager packageManager = context.getPackageManager(); + final String packageName = applicationInfo.packageName; + final Drawable bannerDrawable = packageManager.getDrawable(packageName, resId, + applicationInfo); + if (bannerDrawable == null) { + return null; + } + + final boolean isImageWidthOverScreenLength = + bannerDrawable.getIntrinsicWidth() > getScreenWidthPixels(context); + final boolean isImageHeightOverScreenLength = + bannerDrawable.getIntrinsicHeight() > getScreenHeightPixels(context); + + return (isImageWidthOverScreenLength || isImageHeightOverScreenLength) + ? null + : bannerDrawable; + } + + /** + * Gets the width of the screen. + * + * @param context the current context. + * @return the width of the screen in term of pixels. + */ + private static int getScreenWidthPixels(@NonNull Context context) { + final Resources resources = context.getResources(); + final int screenWidthDp = resources.getConfiguration().screenWidthDp; + + return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenWidthDp, + resources.getDisplayMetrics())); + } + + /** + * Gets the height of the screen. + * + * @param context the current context. + * @return the height of the screen in term of pixels. + */ + private static int getScreenHeightPixels(@NonNull Context context) { + final Resources resources = context.getResources(); + final int screenHeightDp = resources.getConfiguration().screenHeightDp; + + return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, screenHeightDp, + resources.getDisplayMetrics())); + } +} diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 82fdb90be165..b51bbdf62286 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2012,15 +2012,16 @@ public class ActivityManager { /** See {@link android.view.Surface.Rotation} */ @Surface.Rotation private int mRotation; + /** The size of the snapshot before scaling */ + private final Point mTaskSize; private final Rect mContentInsets; - // Whether this snapshot is a down-sampled version of the full resolution, used mainly for - // low-ram devices + // Whether this snapshot is a down-sampled version of the high resolution snapshot, used + // mainly for loading snapshots quickly from disk when user is flinging fast private final boolean mIsLowResolution; // Whether or not the snapshot is a real snapshot or an app-theme generated snapshot due to // the task having a secure window or having previews disabled private final boolean mIsRealSnapshot; private final int mWindowingMode; - private final float mScale; private final int mSystemUiVisibility; private final boolean mIsTranslucent; // Must be one of the named color spaces, otherwise, always use SRGB color space. @@ -2028,9 +2029,9 @@ public class ActivityManager { public TaskSnapshot(long id, @NonNull ComponentName topActivityComponent, GraphicBuffer snapshot, - @NonNull ColorSpace colorSpace, int orientation, int rotation, Rect contentInsets, - boolean isLowResolution, float scale, boolean isRealSnapshot, int windowingMode, - int systemUiVisibility, boolean isTranslucent) { + @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize, + Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot, + int windowingMode, int systemUiVisibility, boolean isTranslucent) { mId = id; mTopActivityComponent = topActivityComponent; mSnapshot = snapshot; @@ -2038,9 +2039,9 @@ public class ActivityManager { ? ColorSpace.get(ColorSpace.Named.SRGB) : colorSpace; mOrientation = orientation; mRotation = rotation; + mTaskSize = new Point(taskSize); mContentInsets = new Rect(contentInsets); mIsLowResolution = isLowResolution; - mScale = scale; mIsRealSnapshot = isRealSnapshot; mWindowingMode = windowingMode; mSystemUiVisibility = systemUiVisibility; @@ -2057,9 +2058,9 @@ public class ActivityManager { : ColorSpace.get(ColorSpace.Named.SRGB); mOrientation = source.readInt(); mRotation = source.readInt(); + mTaskSize = source.readParcelable(null /* classLoader */); mContentInsets = source.readParcelable(null /* classLoader */); mIsLowResolution = source.readBoolean(); - mScale = source.readFloat(); mIsRealSnapshot = source.readBoolean(); mWindowingMode = source.readInt(); mSystemUiVisibility = source.readInt(); @@ -2111,6 +2112,14 @@ public class ActivityManager { } /** + * @return The size of the task at the point this snapshot was taken. + */ + @UnsupportedAppUsage + public Point getTaskSize() { + return mTaskSize; + } + + /** * @return The system/content insets on the snapshot. These can be clipped off in order to * remove any areas behind system bars in the snapshot. */ @@ -2159,14 +2168,6 @@ public class ActivityManager { return mSystemUiVisibility; } - /** - * @return The scale this snapshot was taken in. - */ - @UnsupportedAppUsage - public float getScale() { - return mScale; - } - @Override public int describeContents() { return 0; @@ -2180,9 +2181,9 @@ public class ActivityManager { dest.writeInt(mColorSpace.getId()); dest.writeInt(mOrientation); dest.writeInt(mRotation); + dest.writeParcelable(mTaskSize, 0); dest.writeParcelable(mContentInsets, 0); dest.writeBoolean(mIsLowResolution); - dest.writeFloat(mScale); dest.writeBoolean(mIsRealSnapshot); dest.writeInt(mWindowingMode); dest.writeInt(mSystemUiVisibility); @@ -2200,9 +2201,11 @@ public class ActivityManager { + " mColorSpace=" + mColorSpace.toString() + " mOrientation=" + mOrientation + " mRotation=" + mRotation + + " mTaskSize=" + mTaskSize.toString() + " mContentInsets=" + mContentInsets.toShortString() - + " mIsLowResolution=" + mIsLowResolution + " mScale=" + mScale - + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode + + " mIsLowResolution=" + mIsLowResolution + + " mIsRealSnapshot=" + mIsRealSnapshot + + " mWindowingMode=" + mWindowingMode + " mSystemUiVisibility=" + mSystemUiVisibility + " mIsTranslucent=" + mIsTranslucent; } @@ -2224,9 +2227,8 @@ public class ActivityManager { private ColorSpace mColorSpace; private int mOrientation; private int mRotation; + private Point mTaskSize; private Rect mContentInsets; - private boolean mIsLowResolution; - private float mScaleFraction; private boolean mIsRealSnapshot; private int mWindowingMode; private int mSystemUiVisibility; @@ -2263,25 +2265,16 @@ public class ActivityManager { return this; } - public Builder setContentInsets(Rect contentInsets) { - mContentInsets = contentInsets; - return this; - } - /** - * Set to true if this is a low-resolution snapshot stored in *_reduced.jpg. + * Sets the original size of the task */ - public Builder setIsLowResolution(boolean isLowResolution) { - mIsLowResolution = isLowResolution; + public Builder setTaskSize(Point size) { + mTaskSize = size; return this; } - public float getScaleFraction() { - return mScaleFraction; - } - - public Builder setScaleFraction(float scaleFraction) { - mScaleFraction = scaleFraction; + public Builder setContentInsets(Rect contentInsets) { + mContentInsets = contentInsets; return this; } @@ -2322,9 +2315,12 @@ public class ActivityManager { mColorSpace, mOrientation, mRotation, + mTaskSize, mContentInsets, - mIsLowResolution, - mScaleFraction, + // When building a TaskSnapshot with the Builder class, isLowResolution + // is always false. Low-res snapshots are only created when loading from + // disk. + false /* isLowResolution */, mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index d48b35b6f0c8..fb315add36d2 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -215,8 +215,7 @@ public class ActivityTaskManager { public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, boolean animate, Rect initialBounds, boolean showRecents) throws SecurityException { try { - return getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop, - animate, initialBounds, showRecents); + return getService().setTaskWindowingModeSplitScreenPrimary(taskId, toTop); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 8f02f1555edf..a53fc3508001 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -6910,11 +6910,7 @@ public class AppOpsManager { * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. */ public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) { - try { - return mService.checkOperationRaw(strOpToOp(op), uid, packageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return unsafeCheckOpRawNoThrow(op, uid, packageName); } /** @@ -6923,8 +6919,17 @@ public class AppOpsManager { * {@link #MODE_FOREGROUND}. */ public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) { + return unsafeCheckOpRawNoThrow(strOpToOp(op), uid, packageName); + } + + /** + * Returns the <em>raw</em> mode associated with the op. + * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}. + * @hide + */ + public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) { try { - return mService.checkOperationRaw(strOpToOp(op), uid, packageName); + return mService.checkOperationRaw(op, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 4f41f8bbfacd..969ea707d434 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -675,7 +675,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public int checkPermission(String permName, String pkgName) { return PermissionManager - .checkPackageNamePermission(permName, pkgName); + .checkPackageNamePermission(permName, pkgName, getUserId()); } @Override diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 96edca19afa7..2873b10e60c8 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1397,9 +1397,9 @@ class ContextImpl extends Context { } @Override - public void sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, - Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, - String initialData, @Nullable Bundle initialExtras) { + public void sendOrderedBroadcast(Intent intent, int initialCode, String receiverPermission, + String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, + String initialData, @Nullable Bundle initialExtras, Bundle options) { int intAppOp = AppOpsManager.OP_NONE; if (!TextUtils.isEmpty(receiverAppOp)) { intAppOp = AppOpsManager.strOpToOp(receiverAppOp); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 463c8c9a4528..6f0611e68cda 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -528,29 +528,6 @@ interface IActivityManager { boolean unlockUser(int userid, in byte[] token, in byte[] secret, in IProgressListener listener); void killPackageDependents(in String packageName, int userId); - /** - * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change. - * - * @param dockedBounds The bounds for the docked stack. - * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked stack, which - * might be different from the stack bounds to allow more - * flexibility while resizing, or {@code null} if they should be the - * same as the stack bounds. - * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets. - * When resizing, we usually "freeze" the layout of a task. To - * achieve that, we also need to "freeze" the insets, which - * gets achieved by changing task bounds but not bounds used - * to calculate the insets in this transient state - * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or - * {@code null} if they should be the same as the stack bounds. - * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other - * stacks. - * @throws RemoteException - */ - @UnsupportedAppUsage - void resizeDockedStack(in Rect dockedBounds, in Rect tempDockedTaskBounds, - in Rect tempDockedTaskInsetBounds, - in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds); @UnsupportedAppUsage void removeStack(int stackId); void makePackageIdle(String packageName, int userId); diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 266a06a7aac4..7c8926341555 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -244,8 +244,7 @@ interface IActivityTaskManager { */ boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop); void moveTaskToStack(int taskId, int stackId, boolean toTop); - boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, - boolean animate, in Rect initialBounds, boolean showRecents); + boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop); /** * Removes stacks in the input windowing modes from the system if they are of activity type * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED diff --git a/core/java/android/app/compat/ChangeIdStateCache.java b/core/java/android/app/compat/ChangeIdStateCache.java new file mode 100644 index 000000000000..9ef63f6587f0 --- /dev/null +++ b/core/java/android/app/compat/ChangeIdStateCache.java @@ -0,0 +1,86 @@ +/* + * 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.app.compat; + +import android.app.PropertyInvalidatedCache; +import android.content.Context; +import android.os.Binder; +import android.os.RemoteException; +import android.os.ServiceManager; + +import com.android.internal.compat.IPlatformCompat; + +/** + * Handles caching of calls to {@link com.android.internal.compat.IPlatformCompat} + * @hide + */ +public final class ChangeIdStateCache + extends PropertyInvalidatedCache<ChangeIdStateQuery, Boolean> { + private static final String CACHE_KEY = "cache_key.is_compat_change_enabled"; + private static final int MAX_ENTRIES = 20; + private static boolean sDisabled = false; + + /** @hide */ + public ChangeIdStateCache() { + super(MAX_ENTRIES, CACHE_KEY); + } + + /** + * Disable cache. + * + * <p>Should only be used in unit tests. + * @hide + */ + public static void disable() { + sDisabled = true; + } + + /** + * Invalidate the cache. + * + * <p>Can only be called by the system server process. + * @hide + */ + public static void invalidate() { + if (!sDisabled) { + PropertyInvalidatedCache.invalidateCache(CACHE_KEY); + } + } + + @Override + protected Boolean recompute(ChangeIdStateQuery query) { + IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( + ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); + final long token = Binder.clearCallingIdentity(); + try { + if (query.type == ChangeIdStateQuery.QUERY_BY_PACKAGE_NAME) { + return platformCompat.isChangeEnabledByPackageName(query.changeId, + query.packageName, + query.userId); + } else if (query.type == ChangeIdStateQuery.QUERY_BY_UID) { + return platformCompat.isChangeEnabledByUid(query.changeId, query.uid); + } else { + throw new IllegalArgumentException("Invalid query type: " + query.type); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } finally { + Binder.restoreCallingIdentity(token); + } + throw new IllegalStateException("Could not recompute value!"); + } +} diff --git a/core/java/android/app/compat/ChangeIdStateQuery.java b/core/java/android/app/compat/ChangeIdStateQuery.java new file mode 100644 index 000000000000..3c245b16f6d6 --- /dev/null +++ b/core/java/android/app/compat/ChangeIdStateQuery.java @@ -0,0 +1,90 @@ +/* + * 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.app.compat; + +import android.annotation.IntDef; +import android.annotation.NonNull; + +import com.android.internal.annotations.Immutable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + + +/** + * A key type for caching calls to {@link com.android.internal.compat.IPlatformCompat} + * + * <p>For {@link com.android.internal.compat.IPlatformCompat#isChangeEnabledByPackageName} + * and {@link com.android.internal.compat.IPlatformCompat#isChangeEnabledByUid} + * + * @hide + */ +@Immutable +final class ChangeIdStateQuery { + + static final int QUERY_BY_PACKAGE_NAME = 0; + static final int QUERY_BY_UID = 1; + @IntDef({QUERY_BY_PACKAGE_NAME, QUERY_BY_UID}) + @Retention(RetentionPolicy.SOURCE) + @interface QueryType {} + + public @QueryType int type; + public long changeId; + public String packageName; + public int uid; + public int userId; + + private ChangeIdStateQuery(@QueryType int type, long changeId, String packageName, + int uid, int userId) { + this.type = type; + this.changeId = changeId; + this.packageName = packageName; + this.uid = uid; + this.userId = userId; + } + + static ChangeIdStateQuery byPackageName(long changeId, @NonNull String packageName, + int userId) { + return new ChangeIdStateQuery(QUERY_BY_PACKAGE_NAME, changeId, packageName, 0, userId); + } + + static ChangeIdStateQuery byUid(long changeId, int uid) { + return new ChangeIdStateQuery(QUERY_BY_UID, changeId, null, uid, 0); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if ((other == null) || !(other instanceof ChangeIdStateQuery)) { + return false; + } + final ChangeIdStateQuery that = (ChangeIdStateQuery) other; + return this.type == that.type + && this.changeId == that.changeId + && Objects.equals(this.packageName, that.packageName) + && this.uid == that.uid + && this.userId == that.userId; + } + + @Override + public int hashCode() { + return Objects.hash(type, changeId, packageName, uid, userId); + } +} diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java index e289a2775b79..0d5e45f9e5d4 100644 --- a/core/java/android/app/compat/CompatChanges.java +++ b/core/java/android/app/compat/CompatChanges.java @@ -19,14 +19,8 @@ package android.app.compat; import android.annotation.NonNull; import android.annotation.SystemApi; import android.compat.Compatibility; -import android.content.Context; -import android.os.Binder; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; -import com.android.internal.compat.IPlatformCompat; - /** * CompatChanges APIs - to be used by platform code only (including mainline * modules). @@ -35,6 +29,7 @@ import com.android.internal.compat.IPlatformCompat; */ @SystemApi public final class CompatChanges { + private static final ChangeIdStateCache QUERY_CACHE = new ChangeIdStateCache(); private CompatChanges() {} /** @@ -69,17 +64,8 @@ public final class CompatChanges { */ public static boolean isChangeEnabled(long changeId, @NonNull String packageName, @NonNull UserHandle user) { - IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( - ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); - final long token = Binder.clearCallingIdentity(); - try { - return platformCompat.isChangeEnabledByPackageName(changeId, packageName, - user.getIdentifier()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } finally { - Binder.restoreCallingIdentity(token); - } + return QUERY_CACHE.query(ChangeIdStateQuery.byPackageName(changeId, packageName, + user.getIdentifier())); } /** @@ -101,15 +87,7 @@ public final class CompatChanges { * @return {@code true} if the change is enabled for the current app. */ public static boolean isChangeEnabled(long changeId, int uid) { - IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( - ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); - final long token = Binder.clearCallingIdentity(); - try { - return platformCompat.isChangeEnabledByUid(changeId, uid); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } finally { - Binder.restoreCallingIdentity(token); - } + return QUERY_CACHE.query(ChangeIdStateQuery.byUid(changeId, uid)); } + } diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java index f0eedf3d18f2..7f436401dbf4 100644 --- a/core/java/android/app/prediction/AppPredictor.java +++ b/core/java/android/app/prediction/AppPredictor.java @@ -260,6 +260,7 @@ public final class AppPredictor { Log.e(TAG, "Failed to notify app target event", e); e.rethrowAsRuntimeException(); } + mRegisteredCallbacks.clear(); } else { throw new IllegalStateException("This client has already been destroyed."); } diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 6dea1c69ce86..ccd8199b8373 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -182,6 +182,16 @@ public class AppWidgetManager { public static final String EXTRA_APPWIDGET_ID = "appWidgetId"; /** + * A bundle extra that contains whether or not an app has finished restoring a widget. + * <p> After restore, the app should set OPTION_APPWIDGET_RESTORE_COMPLETED to true on its + * widgets followed by calling {@link #updateAppWidget} to update the views. + * + * @see #updateAppWidgetOptions(int, Bundle) + */ + public static final String OPTION_APPWIDGET_RESTORE_COMPLETED = "appWidgetRestoreCompleted"; + + + /** * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance. */ public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth"; diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java index ab91edfeca24..a5d2198a6e17 100644 --- a/core/java/android/appwidget/AppWidgetProvider.java +++ b/core/java/android/appwidget/AppWidgetProvider.java @@ -200,6 +200,9 @@ public class AppWidgetProvider extends BroadcastReceiver { * provider can immediately generate new RemoteViews suitable for its newly-restored set * of instances. * + * <p>In addition, you should set {@link AppWidgetManager#OPTION_APPWIDGET_RESTORE_COMPLETED} + * to true indicate if a widget has been restored successfully from the provider's side. + * * {@more} * * @param context diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index 1f89ddf0afc7..277a5a8f1625 100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java @@ -278,16 +278,19 @@ public class BluetoothPbap implements BluetoothProfile { } /** - * Pbap does not store connection policy, so this function only disconnects pbap if - * connectionPolicy is {@link #CONNECTION_POLICY_FORBIDDEN}. + * Set connection policy of the profile and tries to disconnect it if connectionPolicy is + * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} * * <p> The device should already be paired. - * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, - * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} + * Connection policy can be one of: + * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, + * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, + * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN} * * @param device Paired bluetooth device - * @param connectionPolicy determines whether to disconnect the device - * @return true if pbap is successfully disconnected, false otherwise + * @param connectionPolicy is the connection policy to set to for this profile + * @return true if connectionPolicy is set, false on error + * * @hide */ @SystemApi diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index b748cfa775ed..c7f42cb85943 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -3827,6 +3827,18 @@ public abstract class ContentResolver implements ContentInterface { return queryArgs; } + /** @hide */ + public static @NonNull Bundle includeSqlSelectionArgs(@NonNull Bundle queryArgs, + @Nullable String selection, @Nullable String[] selectionArgs) { + if (selection != null) { + queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection); + } + if (selectionArgs != null) { + queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs); + } + return queryArgs; + } + /** * Returns structured sort args formatted as an SQL sort clause. * diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 536b6c33b142..a8f7610ecaf0 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2543,12 +2543,13 @@ public abstract class Context { * * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) * @see android.app.BroadcastOptions + * @hide */ - public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, + public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, int initialCode, @Nullable String receiverPermission, @Nullable String receiverAppOp, - @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver, - @Nullable Handler scheduler, int initialCode, @Nullable String initialData, - @Nullable Bundle initialExtras) { + @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, + @Nullable String initialData, @Nullable Bundle initialExtras, + @Nullable Bundle options) { throw new RuntimeException("Not implemented. Must override in a subclass."); } diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index e5381ea0dd41..91d214badd2d 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -600,13 +600,13 @@ public class ContextWrapper extends Context { } @Override - public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, + public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent, int initialCode, @Nullable String receiverPermission, @Nullable String receiverAppOp, - @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver, - @Nullable Handler scheduler, int initialCode, @Nullable String initialData, - @Nullable Bundle initialExtras) { - mBase.sendOrderedBroadcast(intent, receiverPermission, receiverAppOp, options, - resultReceiver, scheduler, initialCode, initialData, initialExtras); + @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, + @Nullable String initialData, @Nullable Bundle initialExtras, + @Nullable Bundle options) { + mBase.sendOrderedBroadcast(intent, initialCode, receiverPermission, receiverAppOp, + resultReceiver, scheduler, initialData, initialExtras, options); } @Override diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index 55a6cab2f2d5..62815ddcfc19 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -138,6 +138,7 @@ public final class OverlayInfo implements Parcelable { * * @hide */ + @NonNull public final String packageName; /** @@ -145,6 +146,7 @@ public final class OverlayInfo implements Parcelable { * * @hide */ + @NonNull public final String targetPackageName; /** @@ -165,6 +167,7 @@ public final class OverlayInfo implements Parcelable { * Full path to the base APK for this overlay package * @hide */ + @NonNull public final String baseCodePath; /** @@ -292,6 +295,7 @@ public final class OverlayInfo implements Parcelable { return targetOverlayableName; } + @SuppressWarnings("ConstantConditions") private void ensureValidState() { if (packageName == null) { throw new IllegalArgumentException("packageName must not be null"); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f2ec938b3d9d..fa751d380580 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -7853,11 +7853,16 @@ public abstract class PackageManager { /** * Returns if the provided drawable represents the default activity icon provided by the system. * - * PackageManager provides a default icon for any package/activity if the app itself does not - * define one or if the system encountered any error when loading the icon. + * PackageManager silently returns a default application icon for any package/activity if the + * app itself does not define one or if the system encountered any error when loading the icon. + * + * Developers can use this to check implement app specific logic around retrying or caching. * * @return true if the drawable represents the default activity icon, false otherwise * @see #getDefaultActivityIcon() + * @see PackageItemInfo#loadDefaultIcon(PackageManager) + * @see #getActivityIcon + * @see LauncherActivityInfo#getIcon(int) */ public boolean isDefaultApplicationIcon(@NonNull Drawable drawable) { int resId = drawable instanceof AdaptiveIconDrawable diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java index 29d960be1892..f65b80ab2229 100644 --- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java +++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java @@ -40,11 +40,6 @@ import android.content.pm.SELinuxUtil; import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.SigningInfo; -import android.content.pm.parsing.ParsingPackage; -import android.os.Environment; -import android.os.UserHandle; - -import com.android.internal.util.ArrayUtils; import android.content.pm.parsing.component.ComponentParseUtils; import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.parsing.component.ParsedComponent; @@ -54,6 +49,10 @@ import android.content.pm.parsing.component.ParsedPermission; import android.content.pm.parsing.component.ParsedPermissionGroup; import android.content.pm.parsing.component.ParsedProvider; import android.content.pm.parsing.component.ParsedService; +import android.os.Environment; +import android.os.UserHandle; + +import com.android.internal.util.ArrayUtils; import libcore.util.EmptyArray; @@ -186,6 +185,22 @@ public class PackageInfoWithoutStateUtils { return null; } + return generateWithoutComponentsUnchecked(pkg, gids, flags, firstInstallTime, + lastUpdateTime, grantedPermissions, state, userId, apexInfo, applicationInfo); + } + + /** + * This bypasses critical checks that are necessary for usage with data passed outside of + * system server. + * + * Prefer {@link #generateWithoutComponents(ParsingPackageRead, int[], int, long, long, Set, + * PackageUserState, int, ApexInfo, ApplicationInfo)}. + */ + @NonNull + public static PackageInfo generateWithoutComponentsUnchecked(ParsingPackageRead pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId, + @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) { PackageInfo pi = new PackageInfo(); pi.packageName = pkg.getPackageName(); pi.splitNames = pkg.getSplitNames(); @@ -317,6 +332,18 @@ public class PackageInfoWithoutStateUtils { return null; } + return generateApplicationInfoUnchecked(pkg, flags, state, userId); + } + + /** + * This bypasses critical checks that are necessary for usage with data passed outside of + * system server. + * + * Prefer {@link #generateApplicationInfo(ParsingPackageRead, int, PackageUserState, int)}. + */ + @NonNull + public static ApplicationInfo generateApplicationInfoUnchecked(@NonNull ParsingPackageRead pkg, + @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) { // Make shallow copy so we can store the metadata/libraries safely ApplicationInfo ai = pkg.toAppInfoWithoutState(); // Init handles data directories @@ -378,6 +405,23 @@ public class PackageInfoWithoutStateUtils { if (applicationInfo == null) { applicationInfo = generateApplicationInfo(pkg, flags, state, userId); } + if (applicationInfo == null) { + return null; + } + + return generateActivityInfoUnchecked(a, applicationInfo); + } + + /** + * This bypasses critical checks that are necessary for usage with data passed outside of + * system server. + * + * Prefer {@link #generateActivityInfo(ParsingPackageRead, ParsedActivity, int, + * PackageUserState, ApplicationInfo, int)}. + */ + @NonNull + public static ActivityInfo generateActivityInfoUnchecked(@NonNull ParsedActivity a, + @NonNull ApplicationInfo applicationInfo) { // Make shallow copies so we can store the metadata safely ActivityInfo ai = new ActivityInfo(); assignSharedFieldsForComponentInfo(ai, a); @@ -431,6 +475,23 @@ public class PackageInfoWithoutStateUtils { if (applicationInfo == null) { applicationInfo = generateApplicationInfo(pkg, flags, state, userId); } + if (applicationInfo == null) { + return null; + } + + return generateServiceInfoUnchecked(s, applicationInfo); + } + + /** + * This bypasses critical checks that are necessary for usage with data passed outside of + * system server. + * + * Prefer {@link #generateServiceInfo(ParsingPackageRead, ParsedService, int, PackageUserState, + * ApplicationInfo, int)}. + */ + @NonNull + public static ServiceInfo generateServiceInfoUnchecked(@NonNull ParsedService s, + @NonNull ApplicationInfo applicationInfo) { // Make shallow copies so we can store the metadata safely ServiceInfo si = new ServiceInfo(); assignSharedFieldsForComponentInfo(si, s); @@ -461,6 +522,24 @@ public class PackageInfoWithoutStateUtils { if (applicationInfo == null) { applicationInfo = generateApplicationInfo(pkg, flags, state, userId); } + if (applicationInfo == null) { + return null; + } + + return generateProviderInfoUnchecked(p, flags, applicationInfo); + } + + /** + * This bypasses critical checks that are necessary for usage with data passed outside of + * system server. + * + * Prefer {@link #generateProviderInfo(ParsingPackageRead, ParsedProvider, int, + * PackageUserState, ApplicationInfo, int)}. + */ + @NonNull + public static ProviderInfo generateProviderInfoUnchecked(@NonNull ParsedProvider p, + @PackageManager.ComponentInfoFlags int flags, + @NonNull ApplicationInfo applicationInfo) { // Make shallow copies so we can store the metadata safely ProviderInfo pi = new ProviderInfo(); assignSharedFieldsForComponentInfo(pi, p); diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java index 9e40f46c3c21..9da0f20d1006 100644 --- a/core/java/android/content/res/ResourcesKey.java +++ b/core/java/android/content/res/ResourcesKey.java @@ -54,7 +54,6 @@ public final class ResourcesKey { private final int mHash; - @UnsupportedAppUsage public ResourcesKey(@Nullable String resDir, @Nullable String[] splitResDirs, @Nullable String[] overlayDirs, @@ -85,6 +84,18 @@ public final class ResourcesKey { mHash = hash; } + @UnsupportedAppUsage + public ResourcesKey(@Nullable String resDir, + @Nullable String[] splitResDirs, + @Nullable String[] overlayDirs, + @Nullable String[] libDirs, + int displayId, + @Nullable Configuration overrideConfig, + @Nullable CompatibilityInfo compatInfo) { + this(resDir, splitResDirs, overlayDirs, libDirs, displayId, overrideConfig, compatInfo, + null); + } + public boolean hasOverrideConfiguration() { return !Configuration.EMPTY.equals(mOverrideConfiguration); } diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 4246b84dc52f..34cc856e000f 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -16,6 +16,7 @@ package android.database; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentValues; @@ -1548,4 +1549,24 @@ public class DatabaseUtils { } return -1; } + + /** + * Escape the given argument for use in a {@code LIKE} statement. + * @hide + */ + public static String escapeForLike(@NonNull String arg) { + // Shamelessly borrowed from com.android.providers.media.util.DatabaseUtils + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < arg.length(); i++) { + final char c = arg.charAt(i); + switch (c) { + case '%': sb.append('\\'); + break; + case '_': sb.append('\\'); + break; + } + sb.append(c); + } + return sb.toString(); + } } diff --git a/core/java/android/debug/AdbManagerInternal.java b/core/java/android/debug/AdbManagerInternal.java index 0bd9f19f91fe..d730129507d7 100644 --- a/core/java/android/debug/AdbManagerInternal.java +++ b/core/java/android/debug/AdbManagerInternal.java @@ -53,4 +53,14 @@ public abstract class AdbManagerInternal { * Returns the file that contains all of the ADB keys and their last used time. */ public abstract File getAdbTempKeysFile(); + + /** + * Starts adbd for a transport. + */ + public abstract void startAdbdForTransport(byte transportType); + + /** + * Stops adbd for a transport. + */ + public abstract void stopAdbdForTransport(byte transportType); } diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 743ce7b46792..85ef4a3392a8 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -131,9 +131,17 @@ public final class CameraManager { } /** - * Return the list of combinations of currently connected camera devices identifiers, which + * Return the set of combinations of currently connected camera device identifiers, which * support configuring camera device sessions concurrently. * + * <p>The devices in these combinations can be concurrently configured by the same + * client camera application. Using these camera devices concurrently by two different + * applications is not guaranteed to be supported, however.</p> + * + * <p>Each device in a combination, is guaranteed to support stream combinations which may be + * obtained by querying {@link #getCameraCharacteristics} for the key + * {@link android.hardware.camera2.CameraCharacteristics#SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS}.</p> + * * <p>The set of combinations may include camera devices that may be in use by other camera API * clients.</p> * @@ -174,7 +182,7 @@ public final class CameraManager { * to be used for exploring the entire space of supported concurrent stream combinations. The * available mandatory concurrent stream combinations may be obtained by querying * {@link #getCameraCharacteristics} for the key - * SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS. </p> + * {@link android.hardware.camera2.CameraCharacteristics#SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS}. </p> * * <p>Note that session parameters will be ignored and calls to * {@link SessionConfiguration#setSessionParameters} are not required.</p> diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java index dbf33cade60c..3d763e630bd0 100644 --- a/core/java/android/hardware/soundtrigger/ConversionUtil.java +++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java @@ -32,7 +32,11 @@ import android.media.soundtrigger_middleware.RecognitionMode; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; import android.media.soundtrigger_middleware.SoundTriggerModuleProperties; +import android.os.SharedMemory; +import android.system.ErrnoException; +import java.io.FileDescriptor; +import java.nio.ByteBuffer; import java.util.Arrays; import java.util.UUID; @@ -105,7 +109,8 @@ class ConversionUtil { aidlModel.type = apiModel.type; aidlModel.uuid = api2aidlUuid(apiModel.uuid); aidlModel.vendorUuid = api2aidlUuid(apiModel.vendorUuid); - aidlModel.data = Arrays.copyOf(apiModel.data, apiModel.data.length); + aidlModel.data = byteArrayToSharedMemory(apiModel.data, "SoundTrigger SoundModel"); + aidlModel.dataSize = apiModel.data.length; return aidlModel; } @@ -352,4 +357,20 @@ class ConversionUtil { } return result; } + + private static @Nullable FileDescriptor byteArrayToSharedMemory(byte[] data, String name) { + if (data.length == 0) { + return null; + } + + try { + SharedMemory shmem = SharedMemory.create(name != null ? name : "", data.length); + ByteBuffer buffer = shmem.mapReadWrite(); + buffer.put(data); + shmem.unmap(buffer); + return shmem.getFileDescriptor(); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } } diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java index ef76c620f3f3..bf641d72eab1 100644 --- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java +++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java @@ -28,6 +28,7 @@ import android.content.res.XmlResourceParser; import android.text.TextUtils; import android.util.ArraySet; import android.util.AttributeSet; +import android.util.Log; import android.util.Slog; import android.util.Xml; @@ -43,6 +44,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; /** * Enrollment information about the different available keyphrases. @@ -116,7 +118,12 @@ public class KeyphraseEnrollmentInfo { /** * List of available keyphrases. */ - final private KeyphraseMetadata[] mKeyphrases; + private final KeyphraseMetadata[] mKeyphrases; + + /** + * Set of UIDs associated with the detected enrollment applications. + */ + private final Set<Integer> mEnrollmentApplicationUids; /** * Map between KeyphraseMetadata and the package name of the enrollment app that provides it. @@ -136,11 +143,13 @@ public class KeyphraseEnrollmentInfo { mParseError = "No enrollment applications found"; mKeyphrasePackageMap = Collections.<KeyphraseMetadata, String>emptyMap(); mKeyphrases = null; + mEnrollmentApplicationUids = Collections.emptySet(); return; } List<String> parseErrors = new LinkedList<String>(); mKeyphrasePackageMap = new HashMap<KeyphraseMetadata, String>(); + mEnrollmentApplicationUids = new ArraySet<>(); for (ResolveInfo ri : ris) { try { ApplicationInfo ai = pm.getApplicationInfo( @@ -162,6 +171,7 @@ public class KeyphraseEnrollmentInfo { getKeyphraseMetadataFromApplicationInfo(pm, ai, parseErrors); if (metadata != null) { mKeyphrasePackageMap.put(metadata, ai.packageName); + mEnrollmentApplicationUids.add(ai.uid); } } catch (PackageManager.NameNotFoundException e) { String error = "error parsing voice enrollment meta-data for " @@ -372,9 +382,22 @@ public class KeyphraseEnrollmentInfo { return null; } + /** + * Tests if the input UID matches a supported enrollment application. + * + * @param uid UID of the caller to test against. + * @return Returns true if input uid matches the uid of a supported enrollment application. + * False if not. + */ + public boolean isUidSupportedEnrollmentApplication(int uid) { + Log.d(TAG, "isUidSupportedEnrollmentApplication: " + toString()); + return mEnrollmentApplicationUids.contains(uid); + } + @Override public String toString() { - return "KeyphraseEnrollmentInfo [Keyphrases=" + mKeyphrasePackageMap.toString() + return "KeyphraseEnrollmentInfo [KeyphrasePackageMap=" + mKeyphrasePackageMap.toString() + + ", enrollmentApplicationUids=" + mEnrollmentApplicationUids.toString() + ", ParseError=" + mParseError + "]"; } } diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 9327b241c6c5..e9de27456f97 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -53,6 +53,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_FINISH_SESSION = 110; private static final int DO_VIEW_CLICKED = 115; private static final int DO_NOTIFY_IME_HIDDEN = 120; + private static final int DO_REMOVE_IME_SURFACE = 130; @UnsupportedAppUsage HandlerCaller mCaller; @@ -136,6 +137,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub mInputMethodSession.notifyImeHidden(); return; } + case DO_REMOVE_IME_SURFACE: { + mInputMethodSession.removeImeSurface(); + return; + } } Log.w(TAG, "Unhandled message code: " + msg.what); } @@ -184,6 +189,11 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } @Override + public void removeImeSurface() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_IME_SURFACE)); + } + + @Override public void updateCursor(Rect newCursor) { mCaller.executeOrSendMessage( mCaller.obtainMessageO(DO_UPDATE_CURSOR, newCursor)); diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index f0b1eaa9f257..b52b437b4557 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -219,22 +219,29 @@ class IInputMethodWrapper extends IInputMethod.Stub case DO_REVOKE_SESSION: inputMethod.revokeSession((InputMethodSession)msg.obj); return; - case DO_SHOW_SOFT_INPUT: - SomeArgs args = (SomeArgs)msg.obj; + case DO_SHOW_SOFT_INPUT: { + final SomeArgs args = (SomeArgs)msg.obj; inputMethod.showSoftInputWithToken( msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1); + args.recycle(); return; - case DO_HIDE_SOFT_INPUT: - inputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj); + } + case DO_HIDE_SOFT_INPUT: { + final SomeArgs args = (SomeArgs) msg.obj; + inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2, + (IBinder) args.arg1); + args.recycle(); return; + } case DO_CHANGE_INPUTMETHOD_SUBTYPE: inputMethod.changeInputMethodSubtype((InputMethodSubtype)msg.obj); return; case DO_CREATE_INLINE_SUGGESTIONS_REQUEST: - args = (SomeArgs) msg.obj; + final SomeArgs args = (SomeArgs) msg.obj; inputMethod.onCreateInlineSuggestionsRequest( (InlineSuggestionsRequestInfo) args.arg1, (IInlineSuggestionsRequestCallback) args.arg2); + args.recycle(); return; } @@ -380,9 +387,9 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override - public void hideSoftInput(int flags, ResultReceiver resultReceiver) { - mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_HIDE_SOFT_INPUT, - flags, resultReceiver)); + public void hideSoftInput(IBinder hideInputToken, int flags, ResultReceiver resultReceiver) { + mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_HIDE_SOFT_INPUT, + flags, hideInputToken, resultReceiver)); } @BinderThread diff --git a/core/java/android/inputmethodservice/InlineSuggestionSession.java b/core/java/android/inputmethodservice/InlineSuggestionSession.java index edae06a0b9df..25e90ee9833c 100644 --- a/core/java/android/inputmethodservice/InlineSuggestionSession.java +++ b/core/java/android/inputmethodservice/InlineSuggestionSession.java @@ -27,6 +27,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import android.view.autofill.AutofillId; import android.view.inputmethod.InlineSuggestionsRequest; import android.view.inputmethod.InlineSuggestionsResponse; @@ -38,11 +39,12 @@ import java.util.function.Consumer; import java.util.function.Supplier; /** - * Maintains an active inline suggestion session. + * Maintains an active inline suggestion session with the autofill manager service. * * <p> - * Each session corresponds to one inline suggestion request, but there may be multiple callbacks - * with the inline suggestions response. + * Each session corresponds to one {@link InlineSuggestionsRequest} and one {@link + * IInlineSuggestionsResponseCallback}, but there may be multiple invocations of the response + * callback for the same field or different fields in the same component. */ class InlineSuggestionSession { @@ -59,6 +61,8 @@ class InlineSuggestionSession { @NonNull private final Supplier<String> mClientPackageNameSupplier; @NonNull + private final Supplier<AutofillId> mClientAutofillIdSupplier; + @NonNull private final Supplier<InlineSuggestionsRequest> mRequestSupplier; @NonNull private final Supplier<IBinder> mHostInputTokenSupplier; @@ -70,6 +74,7 @@ class InlineSuggestionSession { InlineSuggestionSession(@NonNull ComponentName componentName, @NonNull IInlineSuggestionsRequestCallback callback, @NonNull Supplier<String> clientPackageNameSupplier, + @NonNull Supplier<AutofillId> clientAutofillIdSupplier, @NonNull Supplier<InlineSuggestionsRequest> requestSupplier, @NonNull Supplier<IBinder> hostInputTokenSupplier, @NonNull Consumer<InlineSuggestionsResponse> responseConsumer) { @@ -77,6 +82,7 @@ class InlineSuggestionSession { mCallback = callback; mResponseCallback = new InlineSuggestionsResponseCallbackImpl(this); mClientPackageNameSupplier = clientPackageNameSupplier; + mClientAutofillIdSupplier = clientAutofillIdSupplier; mRequestSupplier = requestSupplier; mHostInputTokenSupplier = hostInputTokenSupplier; mResponseConsumer = responseConsumer; @@ -114,21 +120,30 @@ class InlineSuggestionSession { } } - private void handleOnInlineSuggestionsResponse(@NonNull InlineSuggestionsResponse response) { + private void handleOnInlineSuggestionsResponse(@NonNull AutofillId fieldId, + @NonNull InlineSuggestionsResponse response) { if (mInvalidated) { if (DEBUG) { Log.d(TAG, "handleOnInlineSuggestionsResponse() called on invalid session"); } return; } - // TODO(b/149522488): checking the current focused input field to make sure we don't send - // inline responses for previous input field + // TODO(b/149522488): Verify fieldId against {@code mClientAutofillIdSupplier.get()} using + // {@link AutofillId#equalsIgnoreSession(AutofillId)}. Right now, this seems to be + // falsely alarmed quite often, depending whether autofill suggestions arrive earlier + // than the IMS EditorInfo updates or not. if (!mComponentName.getPackageName().equals(mClientPackageNameSupplier.get())) { if (DEBUG) { - Log.d(TAG, "handleOnInlineSuggestionsResponse() called on the wrong package name"); + Log.d(TAG, + "handleOnInlineSuggestionsResponse() called on the wrong package " + + "name: " + mComponentName.getPackageName() + " v.s. " + + mClientPackageNameSupplier.get()); } return; } + if (DEBUG) { + Log.d(TAG, "IME receives response: " + response.getInlineSuggestions().size()); + } mResponseConsumer.accept(response); } @@ -145,13 +160,13 @@ class InlineSuggestionSession { } @Override - public void onInlineSuggestionsResponse(InlineSuggestionsResponse response) - throws RemoteException { + public void onInlineSuggestionsResponse(AutofillId fieldId, + InlineSuggestionsResponse response) { final InlineSuggestionSession session = mInlineSuggestionSession.get(); if (session != null) { session.mHandler.sendMessage(obtainMessage( InlineSuggestionSession::handleOnInlineSuggestionsResponse, session, - response)); + fieldId, response)); } } } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 20a4ab35defe..d27d1382e09d 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -73,6 +73,7 @@ import android.view.Window; import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.AnimationUtils; +import android.view.autofill.AutofillId; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; @@ -459,6 +460,16 @@ public class InputMethodService extends AbstractInputMethodService { */ private IBinder mCurShowInputToken; + /** + * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#hideSoftInput} + * The original app window token is passed from client app window. + * {@link com.android.server.inputmethod.InputMethodManagerService} creates a unique dummy + * token to identify this window. + * This dummy token is only valid for a single call to {@link InputMethodImpl#hideSoftInput}, + * after which it is set {@code null} until next call. + */ + private IBinder mCurHideInputToken; + final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = info -> { onComputeInsets(mTmpInsets); if (isExtractViewShown()) { @@ -500,6 +511,7 @@ public class InputMethodService extends AbstractInputMethodService { public class InputMethodImpl extends AbstractInputMethodImpl { private boolean mSystemCallingShowSoftInput; + private boolean mSystemCallingHideSoftInput; /** * {@inheritDoc} @@ -636,11 +648,32 @@ public class InputMethodService extends AbstractInputMethodService { /** * {@inheritDoc} + * @hide + */ + @MainThread + @Override + public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver, + IBinder hideInputToken) { + mSystemCallingHideSoftInput = true; + mCurHideInputToken = hideInputToken; + hideSoftInput(flags, resultReceiver); + mCurHideInputToken = null; + mSystemCallingHideSoftInput = false; + } + + /** + * {@inheritDoc} */ @MainThread @Override public void hideSoftInput(int flags, ResultReceiver resultReceiver) { if (DEBUG) Log.v(TAG, "hideSoftInput()"); + if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R + && !mSystemCallingHideSoftInput) { + Log.e(TAG, "IME shouldn't call hideSoftInput on itself." + + " Use requestHideSelf(int) itself"); + return; + } final boolean wasVisible = mIsPreRendered ? mDecorViewVisible && mWindowVisible : isInputViewShown(); applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */); @@ -738,6 +771,15 @@ public class InputMethodService extends AbstractInputMethodService { public void setCurrentShowInputToken(IBinder showInputToken) { mCurShowInputToken = showInputToken; } + + /** + * {@inheritDoc} + * @hide + */ + @Override + public void setCurrentHideInputToken(IBinder hideInputToken) { + mCurHideInputToken = hideInputToken; + } } // TODO(b/137800469): Add detailed docs explaining the inline suggestions process. @@ -784,7 +826,7 @@ public class InputMethodService extends AbstractInputMethodService { mInlineSuggestionSession.invalidateSession(); } mInlineSuggestionSession = new InlineSuggestionSession(requestInfo.getComponentName(), - callback, this::getEditorInfoPackageName, + callback, this::getEditorInfoPackageName, this::getEditorInfoAutofillId, () -> onCreateInlineSuggestionsRequest(requestInfo.getUiExtras()), this::getHostInputToken, this::onInlineSuggestionsResponse); } @@ -797,6 +839,14 @@ public class InputMethodService extends AbstractInputMethodService { return null; } + @Nullable + private AutofillId getEditorInfoAutofillId() { + if (mInputEditorInfo != null) { + return mInputEditorInfo.autofillId; + } + return null; + } + /** * Returns the {@link IBinder} input token from the host view root. */ @@ -814,6 +864,13 @@ public class InputMethodService extends AbstractInputMethodService { onPreRenderedWindowVisibilityChanged(false /* setVisible */); } + private void removeImeSurface() { + if (!mShowInputRequested && !mWindowVisible) { + // hiding a window removes its surface. + mWindow.hide(); + } + } + private void setImeWindowStatus(int visibilityFlags, int backDisposition) { mPrivOps.setImeWindowStatus(visibilityFlags, backDisposition); } @@ -932,6 +989,14 @@ public class InputMethodService extends AbstractInputMethodService { public final void notifyImeHidden() { InputMethodService.this.notifyImeHidden(); } + + /** + * Notify IME that surface can be now removed. + * @hide + */ + public final void removeImeSurface() { + InputMethodService.this.removeImeSurface(); + } } /** @@ -2157,7 +2222,8 @@ public class InputMethodService extends AbstractInputMethodService { if (!isVisibilityAppliedUsingInsetsConsumer()) { return; } - mPrivOps.applyImeVisibility(mCurShowInputToken, setVisible); + mPrivOps.applyImeVisibility(setVisible + ? mCurShowInputToken : mCurHideInputToken, setVisible); } private boolean isVisibilityAppliedUsingInsetsConsumer() { diff --git a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java index 31c948a14698..ef138a0c2217 100644 --- a/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java +++ b/core/java/android/inputmethodservice/MultiClientInputMethodClientCallbackAdaptor.java @@ -296,6 +296,12 @@ final class MultiClientInputMethodClientCallbackAdaptor { // no-op for multi-session since IME is responsible controlling navigation bar buttons. reportNotSupported(); } + + @Override + public void removeImeSurface() { + // no-op for multi-session + reportNotSupported(); + } } private static final class MultiClientInputMethodSessionImpl diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index a3c2cd8e7a5d..9ca1c3313670 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -27,8 +27,10 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.app.ActivityManager; import android.content.Context; +import android.os.Handler; import android.util.Log; - +import android.widget.Toast; +import com.android.internal.R; import com.android.internal.util.Preconditions; import libcore.io.IoUtils; @@ -155,12 +157,14 @@ public final class BugreportManager { Preconditions.checkNotNull(executor); Preconditions.checkNotNull(callback); + boolean validScreenshotFd = screenshotFd != null; if (screenshotFd == null) { // Binder needs a valid File Descriptor to be passed screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY); } - DumpstateListener dsListener = new DumpstateListener(executor, callback); + DumpstateListener dsListener = new DumpstateListener(executor, callback, + validScreenshotFd); // Note: mBinder can get callingUid from the binder transaction. mBinder.startBugreport(-1 /* callingUid */, mContext.getOpPackageName(), @@ -221,10 +225,13 @@ public final class BugreportManager { private final class DumpstateListener extends IDumpstateListener.Stub { private final Executor mExecutor; private final BugreportCallback mCallback; + private final boolean mValidScreenshotFd; - DumpstateListener(Executor executor, BugreportCallback callback) { + DumpstateListener(Executor executor, BugreportCallback callback, + boolean validScreenshotFd) { mExecutor = executor; mCallback = callback; + mValidScreenshotFd = validScreenshotFd; } @Override @@ -262,5 +269,20 @@ public final class BugreportManager { Binder.restoreCallingIdentity(identity); } } + + @Override + public void onScreenshotTaken(boolean success) throws RemoteException { + if (!mValidScreenshotFd) { + return; + } + + Handler mainThreadHandler = new Handler(Looper.getMainLooper()); + mainThreadHandler.post( + () -> { + int message = success ? R.string.bugreport_screenshot_success_toast + : R.string.bugreport_screenshot_failure_toast; + Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); + }); + } } } diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java index b08822ddd751..4252fe30f4ad 100644 --- a/core/java/android/os/HidlMemoryUtil.java +++ b/core/java/android/os/HidlMemoryUtil.java @@ -21,14 +21,13 @@ import static android.system.OsConstants.PROT_READ; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.annotation.TestApi; import android.system.ErrnoException; import android.system.Os; import android.util.Log; import com.android.internal.util.Preconditions; +import java.io.FileDescriptor; import java.nio.ByteBuffer; import java.nio.DirectByteBuffer; import java.util.ArrayList; @@ -82,8 +81,7 @@ public final class HidlMemoryUtil { ByteBuffer buffer = shmem.mapReadWrite(); buffer.put(input); shmem.unmap(buffer); - NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); - return new HidlMemory("ashmem", input.length, handle); + return sharedMemoryToHidlMemory(shmem); } catch (ErrnoException e) { throw new RuntimeException(e); } @@ -128,8 +126,7 @@ public final class HidlMemoryUtil { buffer.put(b); } shmem.unmap(buffer); - NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); - return new HidlMemory("ashmem", input.size(), handle); + return sharedMemoryToHidlMemory(shmem); } catch (ErrnoException e) { throw new RuntimeException(e); } @@ -189,6 +186,38 @@ public final class HidlMemoryUtil { return result; } + /** + * Converts a SharedMemory to a HidlMemory without copying. + * + * @param shmem The shared memory object. Null means "empty" and will still result in a non-null + * return value. + * @return The HidlMemory instance. + */ + @NonNull public static HidlMemory sharedMemoryToHidlMemory(@Nullable SharedMemory shmem) { + if (shmem == null) { + return new HidlMemory("ashmem", 0, null); + } + return fileDescriptorToHidlMemory(shmem.getFileDescriptor(), shmem.getSize()); + } + + /** + * Converts a FileDescriptor to a HidlMemory without copying. + * + * @param fd The FileDescriptor object. Null is allowed if size is 0 and will still result in + * a non-null return value. + * @param size The size of the memory buffer. + * @return The HidlMemory instance. + */ + @NonNull public static HidlMemory fileDescriptorToHidlMemory(@Nullable FileDescriptor fd, + int size) { + Preconditions.checkArgument(fd != null || size == 0); + if (fd == null) { + return new HidlMemory("ashmem", 0, null); + } + NativeHandle handle = new NativeHandle(fd, true); + return new HidlMemory("ashmem", size, handle); + } + private static ByteBuffer getBuffer(@NonNull HidlMemory mem) { try { final int size = (int) mem.getSize(); diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index dbe3b7bd1794..d7af1b9faa97 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -529,6 +529,40 @@ public class Process { private static int sPidFdSupported = PIDFD_UNKNOWN; /** + * Value used to indicate that there is no special information about an application launch. App + * launches with this policy will occur through the primary or secondary Zygote with no special + * treatment. + * + * @hide + */ + public static final int ZYGOTE_POLICY_FLAG_EMPTY = 0; + + /** + * Flag used to indicate that an application launch is user-visible and latency sensitive. Any + * launch with this policy will use a Unspecialized App Process Pool if the target Zygote + * supports it. + * + * @hide + */ + public static final int ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE = 1 << 0; + + /** + * Flag used to indicate that the launch is one in a series of app launches that will be + * performed in quick succession. For future use. + * + * @hide + */ + public static final int ZYGOTE_POLICY_FLAG_BATCH_LAUNCH = 1 << 1; + + /** + * Flag used to indicate that the current launch event is for a system process. All system + * processes are equally important, so none of them should be prioritized over the others. + * + * @hide + */ + public static final int ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS = 1 << 2; + + /** * State associated with the zygote process. * @hide */ @@ -567,6 +601,7 @@ public class Process { * @param appDataDir null-ok the data directory of the app. * @param invokeWith null-ok the command to invoke with. * @param packageName null-ok the name of the package this process belongs to. + * @param zygotePolicyFlags Flags used to determine how to launch the application * @param isTopApp whether the process starts for high priority application. * @param disabledCompatChanges null-ok list of disabled compat changes for the process being * started. @@ -590,6 +625,7 @@ public class Process { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, + int zygotePolicyFlags, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> @@ -598,7 +634,7 @@ public class Process { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - /*useUsapPool=*/ true, isTopApp, disabledCompatChanges, + zygotePolicyFlags, isTopApp, disabledCompatChanges, pkgDataInfoMap, zygoteArgs); } @@ -622,8 +658,8 @@ public class Process { return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - /*useUsapPool=*/ false, /*isTopApp=*/ false, disabledCompatChanges, - /* pkgDataInfoMap */ null, zygoteArgs); + /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, /*isTopApp=*/ false, + disabledCompatChanges, /* pkgDataInfoMap */ null, zygoteArgs); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 3846f894c4c3..34cec061edcd 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -16,6 +16,9 @@ package android.os; +import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; +import static android.os.Process.ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS; + import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -119,6 +122,10 @@ public class ZygoteProcess { mUsapPoolSecondarySocketAddress = new LocalSocketAddress(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED); + + // This constructor is used to create the primary and secondary Zygotes, which can support + // Unspecialized App Process Pools. + mUsapPoolSupported = true; } public ZygoteProcess(LocalSocketAddress primarySocketAddress, @@ -128,6 +135,10 @@ public class ZygoteProcess { mUsapPoolSocketAddress = null; mUsapPoolSecondarySocketAddress = null; + + // This constructor is used to create the primary and secondary Zygotes, which CAN NOT + // support Unspecialized App Process Pools. + mUsapPoolSupported = false; } public LocalSocketAddress getPrimarySocketAddress() { @@ -267,6 +278,14 @@ public class ZygoteProcess { private ZygoteState secondaryZygoteState; /** + * If this Zygote supports the creation and maintenance of a USAP pool. + * + * Currently only the primary and secondary Zygotes support USAP pools. Any + * child Zygotes will be unable to create or use a USAP pool. + */ + private final boolean mUsapPoolSupported; + + /** * If the USAP pool should be created and used to start applications. * * Setting this value to false will disable the creation, maintenance, and use of the USAP @@ -308,13 +327,14 @@ public class ZygoteProcess { * @param appDataDir null-ok the data directory of the app. * @param invokeWith null-ok the command to invoke with. * @param packageName null-ok the name of the package this process belongs to. + * @param zygotePolicyFlags Flags used to determine how to launch the application. + * @param isTopApp Whether the process starts for high priority application. * @param disabledCompatChanges null-ok list of disabled compat changes for the process being * started. - * @param zygoteArgs Additional arguments to supply to the zygote process. - * @param isTopApp Whether the process starts for high priority application. * @param pkgDataInfoMap Map from related package names to private data directory * volume UUID and inode number. * + * @param zygoteArgs Additional arguments to supply to the Zygote process. * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure */ @@ -329,7 +349,7 @@ public class ZygoteProcess { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, - boolean useUsapPool, + int zygotePolicyFlags, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> @@ -344,7 +364,7 @@ public class ZygoteProcess { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, - packageName, useUsapPool, isTopApp, disabledCompatChanges, + packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, pkgDataInfoMap, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, @@ -391,7 +411,7 @@ public class ZygoteProcess { */ @GuardedBy("mLock") private Process.ProcessStartResult zygoteSendArgsAndGetResult( - ZygoteState zygoteState, boolean useUsapPool, @NonNull ArrayList<String> args) + ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args) throws ZygoteStartFailedEx { // Throw early if any of the arguments are malformed. This means we can // avoid writing a partial response to the zygote. @@ -417,7 +437,7 @@ public class ZygoteProcess { */ String msgStr = args.size() + "\n" + String.join("\n", args) + "\n"; - if (useUsapPool && mUsapPoolEnabled && canAttemptUsap(args)) { + if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) { try { return attemptUsapSendArgsAndGetResult(zygoteState, msgStr); } catch (IOException ex) { @@ -488,7 +508,43 @@ public class ZygoteProcess { } /** - * Flags that may not be passed to a USAP. + * Test various member properties and parameters to determine if a launch event should be + * handled using an Unspecialized App Process Pool or not. + * + * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the + * Zygote command + * @param args Arguments that will be passed to the Zygote + * @return If the command should be sent to a USAP Pool member or an actual Zygote + */ + private boolean shouldAttemptUsapLaunch(int zygotePolicyFlags, ArrayList<String> args) { + return mUsapPoolSupported + && mUsapPoolEnabled + && policySpecifiesUsapPoolLaunch(zygotePolicyFlags) + && commandSupportedByUsap(args); + } + + /** + * Tests a Zygote policy flag set for various properties that determine if it is eligible for + * being handled by an Unspecialized App Process Pool. + * + * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the + * Zygote command + * @return If the policy allows for use of a USAP pool + */ + private static boolean policySpecifiesUsapPoolLaunch(int zygotePolicyFlags) { + /* + * Zygote USAP Pool Policy: Launch the new process from the USAP Pool iff the launch event + * is latency sensitive but *NOT* a system process. All system processes are equally + * important so we don't want to prioritize one over another. + */ + return (zygotePolicyFlags + & (ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS | ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE)) + == ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; + } + + /** + * Flags that may not be passed to a USAP. These may appear as prefixes to individual Zygote + * arguments. */ private static final String[] INVALID_USAP_FLAGS = { "--query-abi-list", @@ -505,10 +561,11 @@ public class ZygoteProcess { /** * Tests a command list to see if it is valid to send to a USAP. + * * @param args Zygote/USAP command arguments * @return True if the command can be passed to a USAP; false otherwise */ - private static boolean canAttemptUsap(ArrayList<String> args) { + private static boolean commandSupportedByUsap(ArrayList<String> args) { for (String flag : args) { for (String badFlag : INVALID_USAP_FLAGS) { if (flag.startsWith(badFlag)) { @@ -544,6 +601,7 @@ public class ZygoteProcess { * @param startChildZygote Start a sub-zygote. This creates a new zygote process * that has its state cloned from this zygote process. * @param packageName null-ok the name of the package this process belongs to. + * @param zygotePolicyFlags Flags used to determine how to launch the application. * @param isTopApp Whether the process starts for high priority application. * @param disabledCompatChanges a list of disabled compat changes for the process being started. * @param pkgDataInfoMap Map from related package names to private data directory volume UUID @@ -565,7 +623,7 @@ public class ZygoteProcess { @Nullable String invokeWith, boolean startChildZygote, @Nullable String packageName, - boolean useUsapPool, + int zygotePolicyFlags, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> @@ -692,7 +750,7 @@ public class ZygoteProcess { // The USAP pool can not be used if the application will not use the systems graphics // driver. If that driver is requested use the Zygote application start path. return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), - useUsapPool, + zygotePolicyFlags, argsForZygote); } } @@ -722,6 +780,10 @@ public class ZygoteProcess { private long mLastPropCheckTimestamp = 0; private boolean fetchUsapPoolEnabledPropWithMinInterval() { + // If this Zygote doesn't support USAPs there is no need to fetch any + // properties. + if (!mUsapPoolSupported) return false; + final long currentTimestamp = SystemClock.elapsedRealtime(); if (mIsFirstPropCheck @@ -1219,7 +1281,7 @@ public class ZygoteProcess { gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, abi, instructionSet, null /* appDataDir */, null /* invokeWith */, true /* startChildZygote */, null /* packageName */, - false /* useUsapPool */, false /* isTopApp */, + ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */, null /* disabledCompatChanges */, null /* pkgDataInfoMap */, extraArgs); } catch (ZygoteStartFailedEx ex) { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 5d6dc7beb30e..0bd211d70e89 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -561,21 +561,24 @@ public final class PermissionManager { private static final class PackageNamePermissionQuery { final String permName; final String pkgName; + final int uid; - PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName) { + PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName, int uid) { this.permName = permName; this.pkgName = pkgName; + this.uid = uid; } @Override public String toString() { - return String.format("PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s\")", - pkgName, permName); + return String.format( + "PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s, uid=%s\")", + pkgName, permName, uid); } @Override public int hashCode() { - return Objects.hashCode(permName) * 13 + Objects.hashCode(pkgName); + return Objects.hash(permName, pkgName, uid); } @Override @@ -590,15 +593,17 @@ public final class PermissionManager { return false; } return Objects.equals(permName, other.permName) - && Objects.equals(pkgName, other.pkgName); + && Objects.equals(pkgName, other.pkgName) + && uid == other.uid; } } /* @hide */ - private static int checkPackageNamePermissionUncached(String permName, String pkgName) { + private static int checkPackageNamePermissionUncached( + String permName, String pkgName, int uid) { try { return ActivityThread.getPermissionManager().checkPermission( - permName, pkgName, UserHandle.myUserId()); + permName, pkgName, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -611,7 +616,8 @@ public final class PermissionManager { 16, CACHE_KEY_PACKAGE_INFO) { @Override protected Integer recompute(PackageNamePermissionQuery query) { - return checkPackageNamePermissionUncached(query.permName, query.pkgName); + return checkPackageNamePermissionUncached( + query.permName, query.pkgName, query.uid); } }; @@ -620,9 +626,9 @@ public final class PermissionManager { * * @hide */ - public static int checkPackageNamePermission(String permName, String pkgName) { + public static int checkPackageNamePermission(String permName, String pkgName, int uid) { return sPackageNamePermissionCache.query( - new PackageNamePermissionQuery(permName, pkgName)); + new PackageNamePermissionQuery(permName, pkgName, uid)); } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f2d415a2c4a1..fa2b0148b4b5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -53,7 +53,9 @@ import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkScoreManager; import android.net.Uri; +import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiManager; +import android.net.wifi.p2p.WifiP2pManager; import android.os.BatteryManager; import android.os.Binder; import android.os.Build.VERSION_CODES; @@ -10272,7 +10274,8 @@ public final class Settings { /** * Setting to allow scans to be enabled even wifi is turned off for connectivity. * @hide - * @deprecated To be removed. + * @deprecated To be removed. Use {@link WifiManager#setScanAlwaysAvailable(boolean)} for + * setting the value and {@link WifiManager#isScanAlwaysAvailable()} for query. */ public static final String WIFI_SCAN_ALWAYS_AVAILABLE = "wifi_scan_always_enabled"; @@ -10292,7 +10295,9 @@ public final class Settings { * * Type: int (0 for false, 1 for true) * @hide - * @deprecated To be removed. + * @deprecated To be removed. Use {@link SoftApConfiguration.Builder# + * setAutoShutdownEnabled(boolean)} for setting the value and {@link SoftApConfiguration# + * isAutoShutdownEnabled()} for query. */ public static final String SOFT_AP_TIMEOUT_ENABLED = "soft_ap_timeout_enabled"; @@ -10301,7 +10306,8 @@ public final class Settings { * * Type: int (0 for false, 1 for true) * @hide - * @deprecated Use {@link WifiManager#isAutoWakeupEnabled()} instead. + * @deprecated Use {@link WifiManager#setAutoWakeupEnabled(boolean)} for setting the value + * and {@link WifiManager#isAutoWakeupEnabled()} for query. */ @Deprecated @SystemApi @@ -10381,7 +10387,8 @@ public final class Settings { * * Type: int (0 for false, 1 for true) * @hide - * @deprecated To be removed. + * @deprecated Use {@link WifiManager#setScanThrottleEnabled(boolean)} for setting the value + * and {@link WifiManager#isScanThrottleEnabled()} for query. */ public static final String WIFI_SCAN_THROTTLE_ENABLED = "wifi_scan_throttle_enabled"; @@ -10484,7 +10491,8 @@ public final class Settings { * Setting to enable verbose logging in Wi-Fi; disabled by default, and setting to 1 * will enable it. In the future, additional values may be supported. * @hide - * @deprecated To be removed. + * @deprecated Use {@link WifiManager#setVerboseLoggingEnabled(boolean)} for setting the + * value and {@link WifiManager#isVerboseLoggingEnabled()} for query. */ public static final String WIFI_VERBOSE_LOGGING_ENABLED = "wifi_verbose_logging_enabled"; @@ -10553,7 +10561,9 @@ public final class Settings { /** * The Wi-Fi peer-to-peer device name * @hide - * @deprecated To be removed. + * @deprecated Use {@link WifiP2pManager#setDeviceName(WifiP2pManager.Channel, String, + * WifiP2pManager.ActionListener)} for setting the value and + * {@link android.net.wifi.p2p.WifiP2pDevice#deviceName} for query. */ public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name"; diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java index fb8406e99fa0..a9addba375af 100644 --- a/core/java/android/service/autofill/InlinePresentation.java +++ b/core/java/android/service/autofill/InlinePresentation.java @@ -17,6 +17,7 @@ package android.service.autofill; import android.annotation.NonNull; +import android.annotation.Size; import android.app.slice.Slice; import android.os.Parcel; import android.os.Parcelable; @@ -24,6 +25,8 @@ import android.view.inline.InlinePresentationSpec; import com.android.internal.util.DataClass; +import java.util.List; + /** * Wrapper class holding a {@link Slice} and an {@link InlinePresentationSpec} for rendering UI * for an Inline Suggestion. @@ -50,6 +53,18 @@ public final class InlinePresentation implements Parcelable { */ private final boolean mPinned; + /** + * Returns the autofill hints set in the slice. + * + * @hide + */ + @NonNull + @Size(min = 0) + public String[] getAutofillHints() { + List<String> hints = mSlice.getHints(); + return hints.toArray(new String[hints.size()]); + } + // Code below generated by codegen v1.0.14. @@ -214,10 +229,10 @@ public final class InlinePresentation implements Parcelable { }; @DataClass.Generated( - time = 1579726472535L, + time = 1582753782651L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java", - inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)") + inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size(min=0L) java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java index 17e0456df156..fcdefac3163b 100644 --- a/core/java/android/service/autofill/InlineSuggestionRenderService.java +++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java @@ -23,16 +23,13 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.Service; import android.app.slice.Slice; -import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; -import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; -import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.SurfaceControl; @@ -76,35 +73,41 @@ public abstract class InlineSuggestionRenderService extends Service { return; } - final DisplayManager displayManager = getSystemService(DisplayManager.class); - final Display targetDisplay = displayManager.getDisplay(displayId); - if (targetDisplay == null) { - sendResult(callback, /*surface*/ null); - return; - } - final Context displayContext = createDisplayContext(targetDisplay); - - final SurfaceControlViewHost host = new SurfaceControlViewHost(displayContext, - displayContext.getDisplay(), hostInputToken); - final SurfaceControl surface = host.getSurfacePackage().getSurfaceControl(); - - final View suggestionView = onRenderSuggestion(presentation, width, height); - - final InlineSuggestionRoot suggestionRoot = new InlineSuggestionRoot(this, callback); - suggestionRoot.addView(suggestionView); - suggestionRoot.setOnClickListener((v) -> { - try { - callback.onAutofill(); - } catch (RemoteException e) { - Log.w(TAG, "RemoteException calling onAutofill()"); + // When we create the UI it should be for the IME display + updateDisplay(displayId); + try { + final View suggestionView = onRenderSuggestion(presentation, width, height); + if (suggestionView == null) { + try { + callback.onError(); + } catch (RemoteException e) { + Log.w(TAG, "Null suggestion view returned by renderer"); + } + return; } - }); - WindowManager.LayoutParams lp = - new WindowManager.LayoutParams(width, height, - WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT); - host.addView(suggestionRoot, lp); - sendResult(callback, surface); + final InlineSuggestionRoot suggestionRoot = new InlineSuggestionRoot(this, callback); + suggestionRoot.addView(suggestionView); + WindowManager.LayoutParams lp = + new WindowManager.LayoutParams(width, height, + WindowManager.LayoutParams.TYPE_APPLICATION, 0, + PixelFormat.TRANSPARENT); + + final SurfaceControlViewHost host = new SurfaceControlViewHost(this, getDisplay(), + hostInputToken); + host.addView(suggestionRoot, lp); + suggestionRoot.setOnClickListener((v) -> { + try { + callback.onAutofill(); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling onAutofill()"); + } + }); + + sendResult(callback, host.getSurfacePackage().getSurfaceControl()); + } finally { + updateDisplay(Display.DEFAULT_DISPLAY); + } } private void sendResult(@NonNull IInlineSuggestionUiCallback callback, diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index 672b501bbc41..fe792b1efd9f 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -40,6 +40,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.service.autofill.Dataset; import android.service.autofill.FillEventHistory; +import android.service.autofill.InlinePresentation; import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams; import android.util.Log; import android.util.Pair; @@ -557,12 +558,10 @@ public abstract class AugmentedAutofillService extends Service { } } - void reportResult(@Nullable List<Dataset> inlineSuggestionsData) { + void reportResult(@Nullable List<Dataset> inlineSuggestionsData, + @Nullable List<InlinePresentation> inlineActions) { try { - final Dataset[] inlineSuggestions = (inlineSuggestionsData != null) - ? inlineSuggestionsData.toArray(new Dataset[inlineSuggestionsData.size()]) - : null; - mCallback.onSuccess(inlineSuggestions); + mCallback.onSuccess(inlineSuggestionsData, inlineActions); } catch (RemoteException e) { Log.e(TAG, "Error calling back with the inline suggestions data: " + e); } diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java index 19eff57269ae..6b4e1185703c 100644 --- a/core/java/android/service/autofill/augmented/FillCallback.java +++ b/core/java/android/service/autofill/augmented/FillCallback.java @@ -55,14 +55,14 @@ public final class FillCallback { if (response == null) { mProxy.logEvent(AutofillProxy.REPORT_EVENT_NO_RESPONSE); - mProxy.reportResult(null /*inlineSuggestions*/); + mProxy.reportResult(/* inlineSuggestionsData */ null, /* inlineActions */null); return; } List<Dataset> inlineSuggestions = response.getInlineSuggestions(); if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) { mProxy.logEvent(AutofillProxy.REPORT_EVENT_INLINE_RESPONSE); - mProxy.reportResult(inlineSuggestions); + mProxy.reportResult(inlineSuggestions, response.getInlineActions()); return; } diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java index 68ba63ac35a8..b7fdf5ab337f 100644 --- a/core/java/android/service/autofill/augmented/FillResponse.java +++ b/core/java/android/service/autofill/augmented/FillResponse.java @@ -21,6 +21,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Bundle; import android.service.autofill.Dataset; +import android.service.autofill.InlinePresentation; import com.android.internal.util.DataClass; @@ -52,6 +53,13 @@ public final class FillResponse { private @Nullable List<Dataset> mInlineSuggestions; /** + * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no + * inline actions are provided. + */ + @DataClass.PluralOf("inlineAction") + private @Nullable List<InlinePresentation> mInlineActions; + + /** * The client state that {@link AugmentedAutofillService} implementation can put anything in to * identify the request and the response when calling * {@link AugmentedAutofillService#getFillEventHistory()}. @@ -66,6 +74,10 @@ public final class FillResponse { return null; } + private static List<InlinePresentation> defaultInlineActions() { + return null; + } + private static Bundle defaultClientState() { return null; } @@ -74,6 +86,7 @@ public final class FillResponse { /** @hide */ abstract static class BaseBuilder { abstract FillResponse.Builder addInlineSuggestion(@NonNull Dataset value); + abstract FillResponse.Builder addInlineAction(@NonNull InlinePresentation value); } @@ -95,9 +108,11 @@ public final class FillResponse { /* package-private */ FillResponse( @Nullable FillWindow fillWindow, @Nullable List<Dataset> inlineSuggestions, + @Nullable List<InlinePresentation> inlineActions, @Nullable Bundle clientState) { this.mFillWindow = fillWindow; this.mInlineSuggestions = inlineSuggestions; + this.mInlineActions = inlineActions; this.mClientState = clientState; // onConstructed(); // You can define this method to get a callback @@ -125,6 +140,17 @@ public final class FillResponse { } /** + * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no + * inline actions are provided. + * + * @hide + */ + @DataClass.Generated.Member + public @Nullable List<InlinePresentation> getInlineActions() { + return mInlineActions; + } + + /** * The client state that {@link AugmentedAutofillService} implementation can put anything in to * identify the request and the response when calling * {@link AugmentedAutofillService#getFillEventHistory()}. @@ -145,6 +171,7 @@ public final class FillResponse { private @Nullable FillWindow mFillWindow; private @Nullable List<Dataset> mInlineSuggestions; + private @Nullable List<InlinePresentation> mInlineActions; private @Nullable Bundle mClientState; private long mBuilderFieldsSet = 0L; @@ -185,6 +212,27 @@ public final class FillResponse { } /** + * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no + * inline actions are provided. + */ + @DataClass.Generated.Member + public @NonNull Builder setInlineActions(@Nullable List<InlinePresentation> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mInlineActions = value; + return this; + } + + /** @see #setInlineActions */ + @DataClass.Generated.Member + @Override + @NonNull FillResponse.Builder addInlineAction(@NonNull InlinePresentation value) { + if (mInlineActions == null) setInlineActions(new ArrayList<>()); + mInlineActions.add(value); + return this; + } + + /** * The client state that {@link AugmentedAutofillService} implementation can put anything in to * identify the request and the response when calling * {@link AugmentedAutofillService#getFillEventHistory()}. @@ -192,7 +240,7 @@ public final class FillResponse { @DataClass.Generated.Member public @NonNull Builder setClientState(@Nullable Bundle value) { checkNotUsed(); - mBuilderFieldsSet |= 0x4; + mBuilderFieldsSet |= 0x8; mClientState = value; return this; } @@ -200,7 +248,7 @@ public final class FillResponse { /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull FillResponse build() { checkNotUsed(); - mBuilderFieldsSet |= 0x8; // Mark builder used + mBuilderFieldsSet |= 0x10; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mFillWindow = defaultFillWindow(); @@ -209,17 +257,21 @@ public final class FillResponse { mInlineSuggestions = defaultInlineSuggestions(); } if ((mBuilderFieldsSet & 0x4) == 0) { + mInlineActions = defaultInlineActions(); + } + if ((mBuilderFieldsSet & 0x8) == 0) { mClientState = defaultClientState(); } FillResponse o = new FillResponse( mFillWindow, mInlineSuggestions, + mInlineActions, mClientState); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x8) != 0) { + if ((mBuilderFieldsSet & 0x10) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -227,10 +279,10 @@ public final class FillResponse { } @DataClass.Generated( - time = 1580335256422L, + time = 1582682935951L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillResponse.java", - inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nclass BaseBuilder extends java.lang.Object implements []") + inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List<android.service.autofill.InlinePresentation> mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static java.util.List<android.service.autofill.InlinePresentation> defaultInlineActions()\nprivate static android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlinePresentation)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {} diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl index d9837211be19..bf0adcd54ab1 100644 --- a/core/java/android/service/autofill/augmented/IFillCallback.aidl +++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl @@ -20,6 +20,9 @@ import android.os.Bundle; import android.os.ICancellationSignal; import android.service.autofill.Dataset; +import android.service.autofill.InlinePresentation; + +import java.util.List; /** * Interface to receive the result of an autofill request. @@ -28,7 +31,8 @@ import android.service.autofill.Dataset; */ interface IFillCallback { void onCancellable(in ICancellationSignal cancellation); - void onSuccess(in @nullable Dataset[] inlineSuggestionsData); + void onSuccess(in @nullable List<Dataset> inlineSuggestionsData, + in @nullable List<InlinePresentation> inlineActions); boolean isCompleted(); void cancel(); } diff --git a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java index de90b94d7535..2a809b1f099b 100644 --- a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java +++ b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java @@ -18,7 +18,6 @@ package android.service.carrier; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -47,7 +46,6 @@ import java.util.List; * CarrierMessagingService. * @hide */ -@SystemApi public abstract class CarrierMessagingServiceWrapper { // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized. @@ -64,7 +62,6 @@ public abstract class CarrierMessagingServiceWrapper { * @return true upon successfully binding to a carrier messaging service, false otherwise * @hide */ - @SystemApi public boolean bindToCarrierMessagingService(@NonNull Context context, @NonNull String carrierPackageName) { Preconditions.checkState(mCarrierMessagingServiceConnection == null); @@ -82,7 +79,6 @@ public abstract class CarrierMessagingServiceWrapper { * @param context the context * @hide */ - @SystemApi public void disposeConnection(@NonNull Context context) { Preconditions.checkNotNull(mCarrierMessagingServiceConnection); context.unbindService(mCarrierMessagingServiceConnection); @@ -93,7 +89,6 @@ public abstract class CarrierMessagingServiceWrapper { * Implemented by subclasses to use the carrier messaging service once it is ready. * @hide */ - @SystemApi public abstract void onServiceReady(); /** @@ -117,7 +112,6 @@ public abstract class CarrierMessagingServiceWrapper { * @param callback the callback to notify upon completion * @hide */ - @SystemApi public void filterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort, int subId, @NonNull final CarrierMessagingCallbackWrapper callback) { if (mICarrierMessagingService != null) { @@ -142,7 +136,6 @@ public abstract class CarrierMessagingServiceWrapper { * @param callback the callback to notify upon completion * @hide */ - @SystemApi public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress, int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) { if (mICarrierMessagingService != null) { @@ -168,7 +161,6 @@ public abstract class CarrierMessagingServiceWrapper { * @param callback the callback to notify upon completion * @hide */ - @SystemApi public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress, int destPort, int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) { @@ -194,7 +186,6 @@ public abstract class CarrierMessagingServiceWrapper { * @param callback the callback to notify upon completion * @hide */ - @SystemApi public void sendMultipartTextSms(@NonNull List<String> parts, int subId, @NonNull String destAddress, int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) { @@ -220,7 +211,6 @@ public abstract class CarrierMessagingServiceWrapper { * @param callback the callback to notify upon completion * @hide */ - @SystemApi public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location, @NonNull final CarrierMessagingCallbackWrapper callback) { if (mICarrierMessagingService != null) { @@ -244,7 +234,6 @@ public abstract class CarrierMessagingServiceWrapper { * @param callback the callback to notify upon completion * @hide */ - @SystemApi public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location, @NonNull final CarrierMessagingCallbackWrapper callback) { if (mICarrierMessagingService != null) { @@ -276,7 +265,6 @@ public abstract class CarrierMessagingServiceWrapper { * {@link CarrierMessagingServiceWrapper}. * @hide */ - @SystemApi public abstract static class CarrierMessagingCallbackWrapper { /** @@ -289,7 +277,6 @@ public abstract class CarrierMessagingServiceWrapper { * {@see CarrierMessagingService#onReceiveTextSms}. * @hide */ - @SystemApi public void onFilterComplete(int result) { } @@ -304,7 +291,6 @@ public abstract class CarrierMessagingServiceWrapper { * only if result is {@link CarrierMessagingService#SEND_STATUS_OK}. * @hide */ - @SystemApi public void onSendSmsComplete(int result, int messageRef) { } @@ -319,7 +305,6 @@ public abstract class CarrierMessagingServiceWrapper { * {@link CarrierMessagingService#SEND_STATUS_OK}. * @hide */ - @SystemApi public void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) { } @@ -334,7 +319,6 @@ public abstract class CarrierMessagingServiceWrapper { * {@link CarrierMessagingService#SEND_STATUS_OK}. * @hide */ - @SystemApi public void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) { } @@ -346,7 +330,6 @@ public abstract class CarrierMessagingServiceWrapper { * and {@link CarrierMessagingService#SEND_STATUS_ERROR}. * @hide */ - @SystemApi public void onDownloadMmsComplete(int result) { } diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java index 2d1d0ede62ca..dabd9773ec92 100644 --- a/core/java/android/service/controls/Control.java +++ b/core/java/android/service/controls/Control.java @@ -209,61 +209,116 @@ public final class Control implements Parcelable { mStatusText = in.readCharSequence(); } + /** + * @return the identifier for the {@link Control} + */ @NonNull public String getControlId() { return mControlId; } + + /** + * @return type of device represented by this {@link Control}, used to determine the default + * icon and color + */ @DeviceTypes.DeviceType public int getDeviceType() { return mDeviceType; } + /** + * @return the user facing name of the {@link Control} + */ @NonNull public CharSequence getTitle() { return mTitle; } + /** + * @return additional information about the {@link Control}, to appear underneath the title + */ @NonNull public CharSequence getSubtitle() { return mSubtitle; } + /** + * Optional top-level group to help define the {@link Control}'s location, visible to the user. + * If not present, the application name will be used as the top-level group. A structure + * contains zones which contains controls. + * + * @return name of the structure containing the control + */ @Nullable public CharSequence getStructure() { return mStructure; } + /** + * Optional group name to help define the {@link Control}'s location within a structure, + * visible to the user. A structure contains zones which contains controls. + * + * @return name of the zone containing the control + */ @Nullable public CharSequence getZone() { return mZone; } + /** + * @return a {@link PendingIntent} linking to an Activity for the {@link Control} + */ @NonNull public PendingIntent getAppIntent() { return mAppIntent; } + /** + * Optional icon to be shown with the {@link Control}. It is highly recommended + * to let the system default the icon unless the default icon is not suitable. + * + * @return icon to show + */ @Nullable public Icon getCustomIcon() { return mCustomIcon; } + /** + * Optional color to be shown with the {@link Control}. It is highly recommended + * to let the system default the color unless the default is not suitable for the + * application. + * + * @return background color to use + */ @Nullable public ColorStateList getCustomColor() { return mCustomColor; } + /** + * @return status of the {@link Control}, used to convey information about the attempt to + * fetch the current state + */ @Status public int getStatus() { return mStatus; } + /** + * @return instance of {@link ControlTemplate}, that defines how the {@link Control} will + * behave and what interactions are available to the user + */ @NonNull public ControlTemplate getControlTemplate() { return mControlTemplate; } + /** + * @return user-facing text description of the {@link Control}'s status, describing its current + * state + */ @NonNull public CharSequence getStatusText() { return mStatusText; @@ -326,7 +381,10 @@ public final class Control implements Parcelable { /** * Builder class for {@link Control}. * - * This class facilitates the creation of {@link Control} with no state. + * This class facilitates the creation of {@link Control} with no state. Must be used to + * provide controls for {@link ControlsProviderService#createPublisherForAllAvailable} and + * {@link ControlsProviderService#createPublisherForSuggested}. + * * It provides the following defaults for non-optional parameters: * <ul> * <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN} @@ -334,7 +392,7 @@ public final class Control implements Parcelable { * <li> Subtitle: {@code ""} * </ul> * This fixes the values relating to state of the {@link Control} as required by - * {@link ControlsProviderService#loadAvailableControls}: + * {@link ControlsProviderService#createPublisherForAllAvailable}: * <ul> * <li> Status: {@link Status#STATUS_UNKNOWN} * <li> Control template: {@link ControlTemplate#NO_TEMPLATE} @@ -355,8 +413,8 @@ public final class Control implements Parcelable { private @Nullable ColorStateList mCustomColor; /** - * @param controlId the identifier for the {@link Control}. - * @param appIntent the pending intent linking to the device Activity. + * @param controlId the identifier for the {@link Control} + * @param appIntent the pending intent linking to the device Activity */ public StatelessBuilder(@NonNull String controlId, @NonNull PendingIntent appIntent) { @@ -368,6 +426,7 @@ public final class Control implements Parcelable { /** * Creates a {@link StatelessBuilder} using an existing {@link Control} as a base. + * * @param control base for the builder. */ public StatelessBuilder(@NonNull Control control) { @@ -384,7 +443,7 @@ public final class Control implements Parcelable { } /** - * @param controlId the identifier for the {@link Control}. + * @param controlId the identifier for the {@link Control} * @return {@code this} */ @NonNull @@ -394,6 +453,11 @@ public final class Control implements Parcelable { return this; } + /** + * @param deviceType type of device represented by this {@link Control}, used to + * determine the default icon and color + * @return {@code this} + */ @NonNull public StatelessBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) { if (!DeviceTypes.validDeviceType(deviceType)) { @@ -416,6 +480,11 @@ public final class Control implements Parcelable { return this; } + /** + * @param subtitle additional information about the {@link Control}, to appear underneath + * the title + * @return {@code this} + */ @NonNull public StatelessBuilder setSubtitle(@NonNull CharSequence subtitle) { Preconditions.checkNotNull(subtitle); @@ -423,12 +492,27 @@ public final class Control implements Parcelable { return this; } + /** + * Optional top-level group to help define the {@link Control}'s location, visible to the + * user. If not present, the application name will be used as the top-level group. A + * structure contains zones which contains controls. + * + * @param structure name of the structure containing the control + * @return {@code this} + */ @NonNull public StatelessBuilder setStructure(@Nullable CharSequence structure) { mStructure = structure; return this; } + /** + * Optional group name to help define the {@link Control}'s location within a structure, + * visible to the user. A structure contains zones which contains controls. + * + * @param zone name of the zone containing the control + * @return {@code this} + */ @NonNull public StatelessBuilder setZone(@Nullable CharSequence zone) { mZone = zone; @@ -436,7 +520,7 @@ public final class Control implements Parcelable { } /** - * @param appIntent an {@link Intent} linking to an Activity for the {@link Control} + * @param appIntent a {@link PendingIntent} linking to an Activity for the {@link Control} * @return {@code this} */ @NonNull @@ -446,12 +530,27 @@ public final class Control implements Parcelable { return this; } + /** + * Optional icon to be shown with the {@link Control}. It is highly recommended + * to let the system default the icon unless the default icon is not suitable. + * + * @param customIcon icon to show + * @return {@code this} + */ @NonNull public StatelessBuilder setCustomIcon(@Nullable Icon customIcon) { mCustomIcon = customIcon; return this; } + /** + * Optional color to be shown with the {@link Control}. It is highly recommended + * to let the system default the color unless the default is not suitable for the + * application. + * + * @param customColor background color to use + * @return {@code this} + */ @NonNull public StatelessBuilder setCustomColor(@Nullable ColorStateList customColor) { mCustomColor = customColor; @@ -459,7 +558,6 @@ public final class Control implements Parcelable { } /** - * Build a {@link Control} * @return a valid {@link Control} */ @NonNull @@ -480,9 +578,15 @@ public final class Control implements Parcelable { } /** - * Builder class for {@link Control}. + * Builder class for {@link Control} that contains state information. + * + * State information is passed through an instance of a {@link ControlTemplate} and will + * determine how the user can interact with the {@link Control}. User interactions will + * be sent through the method call {@link ControlsProviderService#performControlAction} + * with an instance of {@link ControlAction} to convey any potential new value. + * + * Must be used to provide controls for {@link ControlsProviderService#createPublisherFor}. * - * This class facilitates the creation of {@link Control}. * It provides the following defaults for non-optional parameters: * <ul> * <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN} @@ -522,6 +626,7 @@ public final class Control implements Parcelable { /** * Creates a {@link StatelessBuilder} using an existing {@link Control} as a base. + * * @param control base for the builder. */ public StatefulBuilder(@NonNull Control control) { @@ -551,6 +656,11 @@ public final class Control implements Parcelable { return this; } + /** + * @param deviceType type of device represented by this {@link Control}, used to + * determine the default icon and color + * @return {@code this} + */ @NonNull public StatefulBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) { if (!DeviceTypes.validDeviceType(deviceType)) { @@ -573,6 +683,11 @@ public final class Control implements Parcelable { return this; } + /** + * @param subtitle additional information about the {@link Control}, to appear underneath + * the title + * @return {@code this} + */ @NonNull public StatefulBuilder setSubtitle(@NonNull CharSequence subtitle) { Preconditions.checkNotNull(subtitle); @@ -580,12 +695,27 @@ public final class Control implements Parcelable { return this; } + /** + * Optional top-level group to help define the {@link Control}'s location, visible to the + * user. If not present, the application name will be used as the top-level group. A + * structure contains zones which contains controls. + * + * @param structure name of the structure containing the control + * @return {@code this} + */ @NonNull public StatefulBuilder setStructure(@Nullable CharSequence structure) { mStructure = structure; return this; } + /** + * Optional group name to help define the {@link Control}'s location within a structure, + * visible to the user. A structure contains zones which contains controls. + * + * @param zone name of the zone containing the control + * @return {@code this} + */ @NonNull public StatefulBuilder setZone(@Nullable CharSequence zone) { mZone = zone; @@ -593,7 +723,7 @@ public final class Control implements Parcelable { } /** - * @param appIntent an {@link Intent} linking to an Activity for the {@link Control} + * @param appIntent a {@link PendingIntent} linking to an Activity for the {@link Control} * @return {@code this} */ @NonNull @@ -603,18 +733,38 @@ public final class Control implements Parcelable { return this; } + /** + * Optional icon to be shown with the {@link Control}. It is highly recommended + * to let the system default the icon unless the default icon is not suitable. + * + * @param customIcon icon to show + * @return {@code this} + */ @NonNull public StatefulBuilder setCustomIcon(@Nullable Icon customIcon) { mCustomIcon = customIcon; return this; } + /** + * Optional color to be shown with the {@link Control}. It is highly recommended + * to let the system default the color unless the default is not suitable for the + * application. + * + * @param customColor background color to use + * @return {@code this} + */ @NonNull public StatefulBuilder setCustomColor(@Nullable ColorStateList customColor) { mCustomColor = customColor; return this; } + /** + * @param status status of the {@link Control}, used to convey information about the + * attempt to fetch the current state + * @return {@code this} + */ @NonNull public StatefulBuilder setStatus(@Status int status) { if (status < 0 || status >= NUM_STATUS) { @@ -626,6 +776,12 @@ public final class Control implements Parcelable { return this; } + /** + * @param controlTemplate instance of {@link ControlTemplate}, that defines how the + * {@link Control} will behave and what interactions are + * available to the user + * @return {@code this} + */ @NonNull public StatefulBuilder setControlTemplate(@NonNull ControlTemplate controlTemplate) { Preconditions.checkNotNull(controlTemplate); @@ -633,6 +789,11 @@ public final class Control implements Parcelable { return this; } + /** + * @param statusText user-facing text description of the {@link Control}'s status, + * describing its current state + * @return {@code this} + */ @NonNull public StatefulBuilder setStatusText(@NonNull CharSequence statusText) { Preconditions.checkNotNull(statusText); @@ -640,6 +801,9 @@ public final class Control implements Parcelable { return this; } + /** + * @return a valid {@link Control} + */ @NonNull public Control build() { return new Control(mControlId, diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java index b23d0cd4bd93..9debb37bd0bc 100644 --- a/core/java/android/service/controls/ControlsProviderService.java +++ b/core/java/android/service/controls/ControlsProviderService.java @@ -38,7 +38,6 @@ import android.util.Log; import com.android.internal.util.Preconditions; -import java.util.Collections; import java.util.List; import java.util.concurrent.Flow.Publisher; import java.util.concurrent.Flow.Subscriber; @@ -84,19 +83,6 @@ public abstract class ControlsProviderService extends Service { private RequestHandler mHandler; /** - * Retrieve all available controls, using the stateless builder - * {@link Control.StatelessBuilder} to build each Control, then use the - * provided consumer to callback to the call originator. - * - * @deprecated Removing consumer-based load apis. Use publisherForAllAvailable() instead - */ - @Deprecated - public void loadAvailableControls(@NonNull Consumer<List<Control>> consumer) { - // pending removal - consumer.accept(Collections.emptyList()); - } - - /** * Publisher for all available controls * * Retrieve all available controls. Use the stateless builder {@link Control.StatelessBuilder} @@ -104,11 +90,8 @@ public abstract class ControlsProviderService extends Service { * controls, or {@link Subscriber#onError} for error scenarios. Duplicate Controls will * replace the original. */ - @Nullable - public Publisher<Control> publisherForAllAvailable() { - // will be abstract and @nonnull when consumers are removed - return null; - } + @NonNull + public abstract Publisher<Control> createPublisherForAllAvailable(); /** * (Optional) Publisher for suggested controls @@ -120,7 +103,7 @@ public abstract class ControlsProviderService extends Service { * when done, or {@link Subscriber#onError} for error scenarios. */ @Nullable - public Publisher<Control> publisherForSuggested() { + public Publisher<Control> createPublisherForSuggested() { return null; } @@ -128,10 +111,11 @@ public abstract class ControlsProviderService extends Service { * Return a valid Publisher for the given controlIds. This publisher will be asked to provide * updates for the given list of controlIds as long as the {@link Subscription} is valid. * Calls to {@link Subscriber#onComplete} will not be expected. Instead, wait for the call from - * {@link Subscription#cancel} to indicate that updates are no longer required. + * {@link Subscription#cancel} to indicate that updates are no longer required. It is expected + * that controls provided by this publisher were created using {@link Control.StatefulBuilder}. */ @NonNull - public abstract Publisher<Control> publisherFor(@NonNull List<String> controlIds); + public abstract Publisher<Control> createPublisherFor(@NonNull List<String> controlIds); /** * The user has interacted with a Control. The action is dictated by the type of @@ -177,7 +161,7 @@ public abstract class ControlsProviderService extends Service { } @Override - public boolean onUnbind(@NonNull Intent intent) { + public final boolean onUnbind(@NonNull Intent intent) { mHandler = null; return true; } @@ -198,13 +182,7 @@ public abstract class ControlsProviderService extends Service { final IControlsSubscriber cs = (IControlsSubscriber) msg.obj; final SubscriberProxy proxy = new SubscriberProxy(true, mToken, cs); - Publisher<Control> publisher = - ControlsProviderService.this.publisherForAllAvailable(); - if (publisher == null) { - ControlsProviderService.this.loadAvailableControls(consumerFor(proxy)); - } else { - publisher.subscribe(proxy); - } + ControlsProviderService.this.createPublisherForAllAvailable().subscribe(proxy); break; } @@ -213,7 +191,7 @@ public abstract class ControlsProviderService extends Service { final SubscriberProxy proxy = new SubscriberProxy(true, mToken, cs); Publisher<Control> publisher = - ControlsProviderService.this.publisherForSuggested(); + ControlsProviderService.this.createPublisherForSuggested(); if (publisher == null) { Log.i(TAG, "No publisher provided for suggested controls"); proxy.onComplete(); @@ -228,7 +206,8 @@ public abstract class ControlsProviderService extends Service { final SubscriberProxy proxy = new SubscriberProxy(false, mToken, sMsg.mSubscriber); - ControlsProviderService.this.publisherFor(sMsg.mControlIds).subscribe(proxy); + ControlsProviderService.this.createPublisherFor(sMsg.mControlIds) + .subscribe(proxy); break; } @@ -256,37 +235,6 @@ public abstract class ControlsProviderService extends Service { } }; } - - /** - * Method will be removed during migration to publisher - */ - private Consumer<List<Control>> consumerFor(final Subscriber<Control> subscriber) { - return (@NonNull final List<Control> controls) -> { - Preconditions.checkNotNull(controls); - - subscriber.onSubscribe(new Subscription() { - public void request(long n) { - for (Control control: controls) { - Control c; - if (control == null) { - Log.e(TAG, "onLoad: null control."); - } - if (isStatelessControl(control)) { - c = control; - } else { - Log.w(TAG, "onLoad: control is not stateless."); - c = new Control.StatelessBuilder(control).build(); - } - - subscriber.onNext(c); - } - subscriber.onComplete(); - } - - public void cancel() {} - }); - }; - } } private static boolean isStatelessControl(Control control) { diff --git a/core/java/android/service/controls/DeviceTypes.java b/core/java/android/service/controls/DeviceTypes.java index 8dbb9cf8f9f7..6594d2cf4ba2 100644 --- a/core/java/android/service/controls/DeviceTypes.java +++ b/core/java/android/service/controls/DeviceTypes.java @@ -21,6 +21,9 @@ import android.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +/** + * Device types for {@link Control}. + */ public class DeviceTypes { // Update this when adding new concrete types. Does not count TYPE_UNKNOWN diff --git a/core/java/android/service/controls/actions/BooleanAction.java b/core/java/android/service/controls/actions/BooleanAction.java index 02593353bfc8..b794eadf0f90 100644 --- a/core/java/android/service/controls/actions/BooleanAction.java +++ b/core/java/android/service/controls/actions/BooleanAction.java @@ -19,10 +19,15 @@ package android.service.controls.actions; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; +import android.service.controls.Control; +import android.service.controls.templates.ToggleRangeTemplate; import android.service.controls.templates.ToggleTemplate; /** - * Action sent by a {@link ToggleTemplate} + * Action sent by user toggling a {@link Control} between checked/unchecked. + * + * This action is available when the {@link Control} was constructed with either a + * {@link ToggleTemplate} or a {@link ToggleRangeTemplate}. */ public final class BooleanAction extends ControlAction { @@ -40,8 +45,8 @@ public final class BooleanAction extends ControlAction { } /** - * @param templateId the identifier of the {@link ToggleTemplate} that originated this action. - * @param newState new value for the state displayed by the {@link ToggleTemplate}. + * @param templateId the identifier of the template that originated this action. + * @param newState new value for the state displayed by the template. * @param challengeValue a value sent by the user along with the action to authenticate. {@code} * null is sent when no authentication is needed or has not been * requested. @@ -64,8 +69,7 @@ public final class BooleanAction extends ControlAction { /** * The new state set for the button in the corresponding {@link ToggleTemplate}. * - * @return {@code true} if the button was toggled from an {@code off} state to an {@code on} - * state. + * @return {@code true} if the button was toggled from unchecked to checked. */ public boolean getNewState() { return mNewState; diff --git a/core/java/android/service/controls/actions/CommandAction.java b/core/java/android/service/controls/actions/CommandAction.java index 84d60805c3e9..a560fa4268aa 100644 --- a/core/java/android/service/controls/actions/CommandAction.java +++ b/core/java/android/service/controls/actions/CommandAction.java @@ -19,15 +19,32 @@ package android.service.controls.actions; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; +import android.service.controls.Control; +import android.service.controls.templates.StatelessTemplate; +/** + * A simple {@link ControlAction} indicating that the user has interacted with a {@link Control} + * created using a {@link StatelessTemplate}. + */ public final class CommandAction extends ControlAction { private static final @ActionType int TYPE = TYPE_COMMAND; + /** + * @param templateId the identifier of the {@link StatelessTemplate} that originated this + * action. + * @param challengeValue a value sent by the user along with the action to authenticate. {@code} + * null is sent when no authentication is needed or has not been + * requested. + */ public CommandAction(@NonNull String templateId, @Nullable String challengeValue) { super(templateId, challengeValue); } + /** + * @param templateId the identifier of the {@link StatelessTemplate} that originated this + * action. + */ public CommandAction(@NonNull String templateId) { this(templateId, null); } @@ -40,6 +57,9 @@ public final class CommandAction extends ControlAction { super(b); } + /** + * @return {@link ControlAction#TYPE_COMMAND} + */ @Override public int getActionType() { return TYPE; diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java index 4141da805b5a..45e63d772d73 100644 --- a/core/java/android/service/controls/actions/ControlAction.java +++ b/core/java/android/service/controls/actions/ControlAction.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; +import android.service.controls.Control; import android.service.controls.IControlsActionCallback; import android.service.controls.templates.ControlTemplate; import android.util.Log; @@ -31,7 +32,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * An abstract action that is executed from a {@link ControlTemplate}. + * An abstract action indicating a user interaction with a {@link Control}. * * The action may have a value to authenticate the input, when the provider has requested it to * complete the action. @@ -58,6 +59,9 @@ public abstract class ControlAction { }) public @interface ActionType {}; + /** + * Object returned when there is an unparcelling error. + */ public static final @NonNull ControlAction ERROR_ACTION = new ControlAction() { @Override public int getActionType() { @@ -65,6 +69,9 @@ public abstract class ControlAction { } }; + /** + * The identifier of {@link #ERROR_ACTION} + */ public static final @ActionType int TYPE_ERROR = -1; /** @@ -77,10 +84,19 @@ public abstract class ControlAction { */ public static final @ActionType int TYPE_FLOAT = 2; + /** + * The identifier of {@link MultiFloatAction}. + */ public static final @ActionType int TYPE_MULTI_FLOAT = 3; + /** + * The identifier of {@link ModeAction}. + */ public static final @ActionType int TYPE_MODE = 4; + /** + * The identifier of {@link CommandAction}. + */ public static final @ActionType int TYPE_COMMAND = 5; diff --git a/core/java/android/service/controls/actions/ModeAction.java b/core/java/android/service/controls/actions/ModeAction.java index ca40974d929b..c0e24adb18f3 100644 --- a/core/java/android/service/controls/actions/ModeAction.java +++ b/core/java/android/service/controls/actions/ModeAction.java @@ -19,7 +19,15 @@ package android.service.controls.actions; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; +import android.service.controls.Control; +import android.service.controls.templates.TemperatureControlTemplate; +/** + * Action sent by the user to indicate a change of mode. + * + * This action is available when the {@link Control} was created with a + * {@link TemperatureControlTemplate}. + */ public final class ModeAction extends ControlAction { private static final @ActionType int TYPE = TYPE_MODE; @@ -27,16 +35,32 @@ public final class ModeAction extends ControlAction { private final int mNewMode; + /** + * @return {@link ControlAction#TYPE_MODE}. + */ @Override public int getActionType() { return TYPE; } + /** + * @param templateId the identifier of the {@link TemperatureControlTemplate} that originated + * this action. + * @param newMode new value for the mode. + * @param challengeValue a value sent by the user along with the action to authenticate. {@code} + * null is sent when no authentication is needed or has not been + * requested. + */ public ModeAction(@NonNull String templateId, int newMode, @Nullable String challengeValue) { super(templateId, challengeValue); mNewMode = newMode; } + /** + * @param templateId the identifier of the {@link TemperatureControlTemplate} that originated + * this action. + * @param newMode new value for the mode. + */ public ModeAction(@NonNull String templateId, int newMode) { this(templateId, newMode, null); } diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java index a5156e36f2ce..30efd80db106 100644 --- a/core/java/android/service/controls/templates/ControlTemplate.java +++ b/core/java/android/service/controls/templates/ControlTemplate.java @@ -57,6 +57,9 @@ public abstract class ControlTemplate { } }; + /** + * Object returned when there is an unparcelling error. + */ public static final @NonNull ControlTemplate ERROR_TEMPLATE = new ControlTemplate("") { @Override public int getTemplateType() { @@ -80,6 +83,9 @@ public abstract class ControlTemplate { }) public @interface TemplateType {} + /** + * Type identifier of {@link #ERROR_TEMPLATE}. + */ public static final @TemplateType int TYPE_ERROR = -1; /** @@ -102,10 +108,19 @@ public abstract class ControlTemplate { */ public static final @TemplateType int TYPE_THUMBNAIL = 3; + /** + * Type identifier of {@link ToggleRangeTemplate}. + */ public static final @TemplateType int TYPE_TOGGLE_RANGE = 6; + /** + * Type identifier of {@link TemperatureControlTemplate}. + */ public static final @TemplateType int TYPE_TEMPERATURE = 7; + /** + * Type identifier of {@link StatelessTemplate}. + */ public static final @TemplateType int TYPE_STATELESS = 8; private @NonNull final String mTemplateId; diff --git a/core/java/android/service/controls/templates/RangeTemplate.java b/core/java/android/service/controls/templates/RangeTemplate.java index fe0d16707c9d..0d977d30f7c1 100644 --- a/core/java/android/service/controls/templates/RangeTemplate.java +++ b/core/java/android/service/controls/templates/RangeTemplate.java @@ -19,7 +19,6 @@ package android.service.controls.templates; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; -import android.os.Parcel; import android.service.controls.Control; import android.service.controls.actions.FloatAction; @@ -85,7 +84,7 @@ public final class RangeTemplate extends ControlTemplate { } /** - * Construct a new {@link RangeTemplate} from a {@link Parcel}. + * Construct a new {@link RangeTemplate} from a {@link Bundle}. * * @throws IllegalArgumentException if the parameters passed do not make a valid range * @see RangeTemplate#RangeTemplate(String, float, float, float, float, CharSequence) diff --git a/core/java/android/service/controls/templates/StatelessTemplate.java b/core/java/android/service/controls/templates/StatelessTemplate.java index 3f98beac9cf8..c052412f0e4c 100644 --- a/core/java/android/service/controls/templates/StatelessTemplate.java +++ b/core/java/android/service/controls/templates/StatelessTemplate.java @@ -18,22 +18,36 @@ package android.service.controls.templates; import android.annotation.NonNull; import android.os.Bundle; +import android.service.controls.Control; +import android.service.controls.actions.CommandAction; +/** + * A template for a {@link Control} which has no state. + * + * @see CommandAction + */ public final class StatelessTemplate extends ControlTemplate { + /** + * @return {@link ControlTemplate#TYPE_STATELESS} + */ @Override public int getTemplateType() { return TYPE_STATELESS; } /** - * @param b + * Construct a new {@link StatelessTemplate} from a {@link Bundle} * @hide */ StatelessTemplate(@NonNull Bundle b) { super(b); } + /** + * Construct a new {@link StatelessTemplate} + * @param templateId the identifier for this template + */ public StatelessTemplate(@NonNull String templateId) { super(templateId); } diff --git a/core/java/android/service/controls/templates/TemperatureControlTemplate.java b/core/java/android/service/controls/templates/TemperatureControlTemplate.java index 9d8dca6278c5..0818c7e4fb82 100644 --- a/core/java/android/service/controls/templates/TemperatureControlTemplate.java +++ b/core/java/android/service/controls/templates/TemperatureControlTemplate.java @@ -19,6 +19,7 @@ package android.service.controls.templates; import android.annotation.IntDef; import android.annotation.NonNull; import android.os.Bundle; +import android.service.controls.Control; import android.util.Log; import com.android.internal.util.Preconditions; @@ -26,6 +27,13 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +/** + * A template for a temperature related {@link Control} that supports multiple modes. + * + * Both the current mode and the active mode for the control can be specified. The combination of + * the {@link Control#getDeviceType} and the current and active mode will determine colors and + * transitions for the UI element. + */ public final class TemperatureControlTemplate extends ControlTemplate { private static final String TAG = "ThermostatTemplate"; @@ -51,6 +59,7 @@ public final class TemperatureControlTemplate extends ControlTemplate { public @interface Mode {} private static final int NUM_MODES = 6; + public static final @Mode int MODE_UNKNOWN = 0; public static final @Mode int MODE_OFF = 1; @@ -102,6 +111,18 @@ public final class TemperatureControlTemplate extends ControlTemplate { private final @Mode int mCurrentActiveMode; private final @ModeFlag int mModes; + /** + * Construct a new {@link TemperatureControlTemplate}. + * + * The current and active mode have to be among the ones supported by the flags. + * + * @param templateId the identifier for this template object + * @param controlTemplate a template to use for interaction with the user + * @param currentMode the current mode for the {@link Control} + * @param currentActiveMode the current active mode for the {@link Control} + * @param modesFlag a flag representing the available modes for the {@link Control} + * @throws IllegalArgumentException if the parameters passed do not make a valid template. + */ public TemperatureControlTemplate(@NonNull String templateId, @NonNull ControlTemplate controlTemplate, @Mode int currentMode, @@ -179,6 +200,9 @@ public final class TemperatureControlTemplate extends ControlTemplate { return mModes; } + /** + * @return {@link ControlTemplate#TYPE_TEMPERATURE} + */ @Override public int getTemplateType() { return TYPE; diff --git a/core/java/android/service/controls/templates/ToggleRangeTemplate.java b/core/java/android/service/controls/templates/ToggleRangeTemplate.java index af43b94699d2..cd6a2fc45612 100644 --- a/core/java/android/service/controls/templates/ToggleRangeTemplate.java +++ b/core/java/android/service/controls/templates/ToggleRangeTemplate.java @@ -18,9 +18,16 @@ package android.service.controls.templates; import android.annotation.NonNull; import android.os.Bundle; +import android.service.controls.Control; import com.android.internal.util.Preconditions; +/** + * A template for a {@link Control} supporting toggling and a range. + * + * @see ToggleTemplate + * @see RangeTemplate + */ public final class ToggleRangeTemplate extends ControlTemplate { private static final @TemplateType int TYPE = TYPE_TOGGLE_RANGE; @@ -40,6 +47,12 @@ public final class ToggleRangeTemplate extends ControlTemplate { mRangeTemplate = new RangeTemplate(b.getBundle(KEY_RANGE)); } + /** + * Constructs a new {@link ToggleRangeTemplate}. + * @param templateId the identifier for this template. + * @param button a {@link ControlButton} to use for the toggle interface + * @param range a {@link RangeTemplate} to use for the range interface + */ public ToggleRangeTemplate(@NonNull String templateId, @NonNull ControlButton button, @NonNull RangeTemplate range) { @@ -50,6 +63,14 @@ public final class ToggleRangeTemplate extends ControlTemplate { mRangeTemplate = range; } + /** + * Constructs a new {@link ToggleRangeTemplate}. + * @param templateId the identifier for this template. + * @param checked true if the toggle should be rendered as active. + * @param actionDescription action description for the button. + * @param range {@link RangeTemplate} to use for the range interface + * @see ControlButton + */ public ToggleRangeTemplate(@NonNull String templateId, boolean checked, @NonNull CharSequence actionDescription, @@ -86,6 +107,9 @@ public final class ToggleRangeTemplate extends ControlTemplate { return mControlButton.getActionDescription(); } + /** + * @return {@link ControlTemplate#TYPE_TOGGLE_RANGE} + */ @Override public int getTemplateType() { return TYPE; diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 28f492982a41..002d4b8d195d 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -883,7 +883,7 @@ public class DreamService extends Service implements Window.Callback { * </p> */ public void onWakeUp() { - mActivity.finishAndRemoveTask(); + finish(); } /** {@inheritDoc} */ @@ -904,13 +904,14 @@ public class DreamService extends Service implements Window.Callback { public final void finish() { if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished); - if (mActivity == null) { + if (mActivity != null) { + if (!mActivity.isFinishing()) { + // In case the activity is not finished yet, do it now. + mActivity.finishAndRemoveTask(); + return; + } + } else if (!mWindowless) { Slog.w(TAG, "Finish was called before the dream was attached."); - } else if (!mActivity.isFinishing()) { - // In case the activity is not finished yet, do it now. This can happen if someone calls - // finish() directly, without going through wakeUp(). - mActivity.finishAndRemoveTask(); - return; } if (!mFinished) { @@ -1010,7 +1011,7 @@ public class DreamService extends Service implements Window.Callback { * @param started A callback that will be invoked once onDreamingStarted has completed. */ private void attach(IBinder dreamToken, boolean canDoze, IRemoteCallback started) { - if (mActivity != null) { + if (mDreamToken != null) { Slog.e(TAG, "attach() called when dream with token=" + mDreamToken + " already attached"); return; diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 6562572d0121..0cd96b8ea688 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -19,6 +19,7 @@ package android.service.notification; import android.annotation.CurrentTimeMillisLong; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -37,6 +38,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; +import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -53,6 +55,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; +import android.util.Slog; import android.widget.RemoteViews; import com.android.internal.annotations.GuardedBy; @@ -1566,6 +1569,7 @@ public abstract class NotificationListenerService extends Service { private boolean mCanBubble; private boolean mVisuallyInterruptive; private boolean mIsConversation; + private ShortcutInfo mShortcutInfo; private static final int PARCEL_VERSION = 2; @@ -1599,6 +1603,7 @@ public abstract class NotificationListenerService extends Service { out.writeBoolean(mCanBubble); out.writeBoolean(mVisuallyInterruptive); out.writeBoolean(mIsConversation); + out.writeParcelable(mShortcutInfo, flags); } /** @hide */ @@ -1620,7 +1625,7 @@ public abstract class NotificationListenerService extends Service { mImportance = in.readInt(); mImportanceExplanation = in.readCharSequence(); // may be null mOverrideGroupKey = in.readString(); // may be null - mChannel = (NotificationChannel) in.readParcelable(cl); // may be null + mChannel = in.readParcelable(cl); // may be null mOverridePeople = in.createStringArrayList(); mSnoozeCriteria = in.createTypedArrayList(SnoozeCriterion.CREATOR); mShowBadge = in.readBoolean(); @@ -1633,6 +1638,7 @@ public abstract class NotificationListenerService extends Service { mCanBubble = in.readBoolean(); mVisuallyInterruptive = in.readBoolean(); mIsConversation = in.readBoolean(); + mShortcutInfo = in.readParcelable(cl); } @@ -1840,6 +1846,13 @@ public abstract class NotificationListenerService extends Service { /** * @hide */ + public @Nullable ShortcutInfo getShortcutInfo() { + return mShortcutInfo; + } + + /** + * @hide + */ @VisibleForTesting public void populate(String key, int rank, boolean matchesInterruptionFilter, int visibilityOverride, int suppressedVisualEffects, int importance, @@ -1849,7 +1862,7 @@ public abstract class NotificationListenerService extends Service { int userSentiment, boolean hidden, long lastAudiblyAlertedMs, boolean noisy, ArrayList<Notification.Action> smartActions, ArrayList<CharSequence> smartReplies, boolean canBubble, - boolean visuallyInterruptive, boolean isConversation) { + boolean visuallyInterruptive, boolean isConversation, ShortcutInfo shortcutInfo) { mKey = key; mRank = rank; mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW; @@ -1872,6 +1885,7 @@ public abstract class NotificationListenerService extends Service { mCanBubble = canBubble; mVisuallyInterruptive = visuallyInterruptive; mIsConversation = isConversation; + mShortcutInfo = shortcutInfo; } /** @@ -1898,7 +1912,8 @@ public abstract class NotificationListenerService extends Service { other.mSmartReplies, other.mCanBubble, other.mVisuallyInterruptive, - other.mIsConversation); + other.mIsConversation, + other.mShortcutInfo); } /** @@ -1952,7 +1967,10 @@ public abstract class NotificationListenerService extends Service { && Objects.equals(mSmartReplies, other.mSmartReplies) && Objects.equals(mCanBubble, other.mCanBubble) && Objects.equals(mVisuallyInterruptive, other.mVisuallyInterruptive) - && Objects.equals(mIsConversation, other.mIsConversation); + && Objects.equals(mIsConversation, other.mIsConversation) + // Shortcutinfo doesn't have equals either; use id + && Objects.equals((mShortcutInfo == null ? 0 : mShortcutInfo.getId()), + (other.mShortcutInfo == null ? 0 : other.mShortcutInfo.getId())); } } diff --git a/core/java/android/service/notification/OWNERS b/core/java/android/service/notification/OWNERS new file mode 100644 index 000000000000..2e94be5bf329 --- /dev/null +++ b/core/java/android/service/notification/OWNERS @@ -0,0 +1,4 @@ +juliacr@google.com +beverlyt@google.com +dsandler@android.com +pixel@google.com
\ No newline at end of file diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index a88d389178bf..7d070b1d9df6 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -227,7 +227,6 @@ public class AlwaysOnHotwordDetector { @Nullable private KeyphraseMetadata mKeyphraseMetadata; private final KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo; - private final IVoiceInteractionService mVoiceInteractionService; private final IVoiceInteractionManagerService mModelManagementService; private final SoundTriggerListener mInternalCallback; private final Callback mExternalCallback; @@ -413,14 +412,11 @@ public class AlwaysOnHotwordDetector { * @param text The keyphrase text to get the detector for. * @param locale The java locale for the detector. * @param callback A non-null Callback for receiving the recognition events. - * @param voiceInteractionService The current voice interaction service. * @param modelManagementService A service that allows management of sound models. - * * @hide */ public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback, KeyphraseEnrollmentInfo keyphraseEnrollmentInfo, - IVoiceInteractionService voiceInteractionService, IVoiceInteractionManagerService modelManagementService) { mText = text; mLocale = locale; @@ -428,7 +424,6 @@ public class AlwaysOnHotwordDetector { mExternalCallback = callback; mHandler = new MyHandler(); mInternalCallback = new SoundTriggerListener(mHandler); - mVoiceInteractionService = voiceInteractionService; mModelManagementService = modelManagementService; new RefreshAvailabiltyTask().execute(); } @@ -471,6 +466,8 @@ public class AlwaysOnHotwordDetector { /** * Get the audio capabilities supported by the platform which can be enabled when * starting a recognition. + * Caller must be the active voice interaction service via + * Settings.Secure.VOICE_INTERACTION_SERVICE. * * @see #AUDIO_CAPABILITY_ECHO_CANCELLATION * @see #AUDIO_CAPABILITY_NOISE_SUPPRESSION @@ -488,7 +485,7 @@ public class AlwaysOnHotwordDetector { private int getSupportedAudioCapabilitiesLocked() { try { ModuleProperties properties = - mModelManagementService.getDspModuleProperties(mVoiceInteractionService); + mModelManagementService.getDspModuleProperties(); if (properties != null) { return properties.audioCapabilities; } @@ -501,6 +498,8 @@ public class AlwaysOnHotwordDetector { /** * Starts recognition for the associated keyphrase. + * Caller must be the active voice interaction service via + * Settings.Secure.VOICE_INTERACTION_SERVICE. * * @see #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO * @see #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS @@ -533,6 +532,8 @@ public class AlwaysOnHotwordDetector { /** * Stops recognition for the associated keyphrase. + * Caller must be the active voice interaction service via + * Settings.Secure.VOICE_INTERACTION_SERVICE. * * @return Indicates whether the call succeeded or not. * @throws UnsupportedOperationException if the recognition isn't supported. @@ -565,6 +566,8 @@ public class AlwaysOnHotwordDetector { * stopping recognition. Once the model is unloaded, the value will be lost. * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before calling this * method. + * Caller must be the active voice interaction service via + * Settings.Secure.VOICE_INTERACTION_SERVICE. * * @param modelParam {@link ModelParams} * @param value Value to set @@ -595,6 +598,8 @@ public class AlwaysOnHotwordDetector { * value is returned. See {@link ModelParams} for parameter default values. * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before * calling this method. + * Caller must be the active voice interaction service via + * Settings.Secure.VOICE_INTERACTION_SERVICE. * * @param modelParam {@link ModelParams} * @return value of parameter @@ -617,6 +622,8 @@ public class AlwaysOnHotwordDetector { * Determine if parameter control is supported for the given model handle. * This method should be checked prior to calling {@link AlwaysOnHotwordDetector#setParameter} * or {@link AlwaysOnHotwordDetector#getParameter}. + * Caller must be the active voice interaction service via + * Settings.Secure.VOICE_INTERACTION_SERVICE. * * @param modelParam {@link ModelParams} * @return supported range of parameter, null if not supported @@ -775,7 +782,7 @@ public class AlwaysOnHotwordDetector { int code = STATUS_ERROR; try { - code = mModelManagementService.startRecognition(mVoiceInteractionService, + code = mModelManagementService.startRecognition( mKeyphraseMetadata.id, mLocale.toLanguageTag(), mInternalCallback, new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, recognitionExtra, null /* additional data */, audioCapabilities)); @@ -791,8 +798,8 @@ public class AlwaysOnHotwordDetector { private int stopRecognitionLocked() { int code = STATUS_ERROR; try { - code = mModelManagementService.stopRecognition( - mVoiceInteractionService, mKeyphraseMetadata.id, mInternalCallback); + code = mModelManagementService.stopRecognition(mKeyphraseMetadata.id, + mInternalCallback); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in stopRecognition!", e); } @@ -805,8 +812,8 @@ public class AlwaysOnHotwordDetector { private int setParameterLocked(@ModelParams int modelParam, int value) { try { - int code = mModelManagementService.setParameter(mVoiceInteractionService, - mKeyphraseMetadata.id, modelParam, value); + int code = mModelManagementService.setParameter(mKeyphraseMetadata.id, modelParam, + value); if (code != STATUS_OK) { Slog.w(TAG, "setParameter failed with error code " + code); @@ -820,8 +827,7 @@ public class AlwaysOnHotwordDetector { private int getParameterLocked(@ModelParams int modelParam) { try { - return mModelManagementService.getParameter(mVoiceInteractionService, - mKeyphraseMetadata.id, modelParam); + return mModelManagementService.getParameter(mKeyphraseMetadata.id, modelParam); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -831,8 +837,7 @@ public class AlwaysOnHotwordDetector { private ModelParamRange queryParameterLocked(@ModelParams int modelParam) { try { SoundTrigger.ModelParamRange modelParamRange = - mModelManagementService.queryParameter(mVoiceInteractionService, - mKeyphraseMetadata.id, modelParam); + mModelManagementService.queryParameter(mKeyphraseMetadata.id, modelParam); if (modelParamRange == null) { return null; @@ -966,7 +971,7 @@ public class AlwaysOnHotwordDetector { ModuleProperties dspModuleProperties = null; try { dspModuleProperties = - mModelManagementService.getDspModuleProperties(mVoiceInteractionService); + mModelManagementService.getDspModuleProperties(); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in getDspProperties!", e); } @@ -982,7 +987,7 @@ public class AlwaysOnHotwordDetector { private void internalUpdateEnrolledKeyphraseMetadata() { try { mKeyphraseMetadata = mModelManagementService.getEnrolledKeyphraseMetadata( - mVoiceInteractionService, mText, mLocale.toLanguageTag()); + mText, mLocale.toLanguageTag()); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in internalUpdateEnrolledKeyphraseMetadata", e); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index fc99836b82fd..b54e4d9b876d 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -199,7 +199,7 @@ public class VoiceInteractionService extends Service { throw new IllegalStateException("Not available until onReady() is called"); } try { - mSystemService.showSession(mInterface, args, flags); + mSystemService.showSession(args, flags); } catch (RemoteException e) { } } @@ -302,7 +302,7 @@ public class VoiceInteractionService extends Service { // Allow only one concurrent recognition via the APIs. safelyShutdownHotwordDetector(); mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback, - mKeyphraseEnrollmentInfo, mInterface, mSystemService); + mKeyphraseEnrollmentInfo, mSystemService); } return mHotwordDetector; } @@ -373,7 +373,7 @@ public class VoiceInteractionService extends Service { } try { - mSystemService.setUiHints(mInterface, hints); + mSystemService.setUiHints(hints); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 2c077bbdc772..7238b1244eb3 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -18,7 +18,6 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.Compatibility; import android.compat.annotation.ChangeId; @@ -62,7 +61,6 @@ import java.util.concurrent.Executor; * * @hide */ -@SystemApi @TestApi public class TelephonyRegistryManager { @@ -286,7 +284,6 @@ public class TelephonyRegistryManager { * @param incomingNumber incoming phone number. * @hide */ - @SystemApi @TestApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyCallStateChangedForAllSubscriptions(@CallState int state, @@ -302,7 +299,6 @@ public class TelephonyRegistryManager { * Notify {@link SubscriptionInfo} change. * @hide */ - @SystemApi public void notifySubscriptionInfoChanged() { try { sRegistry.notifySubscriptionInfoChanged(); @@ -315,7 +311,6 @@ public class TelephonyRegistryManager { * Notify opportunistic {@link SubscriptionInfo} change. * @hide */ - @SystemApi public void notifyOpportunisticSubscriptionInfoChanged() { try { sRegistry.notifyOpportunisticSubscriptionInfoChanged(); diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java index 24e7d2b3589b..cbe3734ce5fa 100644 --- a/core/java/android/util/proto/ProtoInputStream.java +++ b/core/java/android/util/proto/ProtoInputStream.java @@ -601,6 +601,12 @@ public final class ProtoInputStream extends ProtoStream { // Limit how much bookkeeping is done by checking how far away the end of the buffer is // and directly accessing buffer up until the end. final int fragment = mEnd - mOffset; + if (fragment < 0) { + throw new ProtoParseException( + "Incomplete varint at offset 0x" + + Integer.toHexString(getOffset()) + + dumpDebugData()); + } for (int i = 0; i < fragment; i++) { byte b = mBuffer[(mOffset + i)]; value |= (b & 0x7FL) << shift; @@ -646,6 +652,12 @@ public final class ProtoInputStream extends ProtoStream { fillBuffer(); // Find the number of bytes available until the end of the chunk or Fixed32 int fragment = (mEnd - mOffset) < bytesLeft ? (mEnd - mOffset) : bytesLeft; + if (fragment < 0) { + throw new ProtoParseException( + "Incomplete fixed32 at offset 0x" + + Integer.toHexString(getOffset()) + + dumpDebugData()); + } incOffset(fragment); bytesLeft -= fragment; while (fragment > 0) { @@ -686,6 +698,12 @@ public final class ProtoInputStream extends ProtoStream { fillBuffer(); // Find the number of bytes available until the end of the chunk or Fixed64 int fragment = (mEnd - mOffset) < bytesLeft ? (mEnd - mOffset) : bytesLeft; + if (fragment < 0) { + throw new ProtoParseException( + "Incomplete fixed64 at offset 0x" + + Integer.toHexString(getOffset()) + + dumpDebugData()); + } incOffset(fragment); bytesLeft -= fragment; while (fragment > 0) { diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java index 7b24ba997307..9a555c161300 100644 --- a/core/java/android/util/proto/ProtoOutputStream.java +++ b/core/java/android/util/proto/ProtoOutputStream.java @@ -32,7 +32,7 @@ import java.io.UnsupportedEncodingException; * <p> * This API is not as convenient or type safe as the standard protobuf * classes. If possible, the best recommended library is to use protobuf lite. - * However, in environements (such as the Android platform itself), a + * However, in environments (such as the Android platform itself), a * more memory efficient version is necessary. * * <p>Each write method takes an ID code from the protoc generated classes diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java index 0ab856ec5b4d..679c912e846f 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -393,22 +393,38 @@ public final class DisplayCutout { return mSafeInsets.equals(ZERO_RECT); } - /** Returns the inset from the top which avoids the display cutout in pixels. */ + /** + * Returns the inset from the top which avoids the display cutout in pixels. + * + * @see WindowInsets.Type#displayCutout() + */ public int getSafeInsetTop() { return mSafeInsets.top; } - /** Returns the inset from the bottom which avoids the display cutout in pixels. */ + /** + * Returns the inset from the bottom which avoids the display cutout in pixels. + * + * @see WindowInsets.Type#displayCutout() + */ public int getSafeInsetBottom() { return mSafeInsets.bottom; } - /** Returns the inset from the left which avoids the display cutout in pixels. */ + /** + * Returns the inset from the left which avoids the display cutout in pixels. + * + * @see WindowInsets.Type#displayCutout() + */ public int getSafeInsetLeft() { return mSafeInsets.left; } - /** Returns the inset from the right which avoids the display cutout in pixels. */ + /** + * Returns the inset from the right which avoids the display cutout in pixels. + * + * @see WindowInsets.Type#displayCutout() + */ public int getSafeInsetRight() { return mSafeInsets.right; } diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index 530dffbf0620..a60a5cca08bd 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -67,11 +67,6 @@ interface IRecentsAnimationController { void setAnimationTargetsBehindSystemBars(boolean behindSystemBars); /** - * Informs the system that the primary split-screen stack should be minimized. - */ - void setSplitScreenMinimized(boolean minimized); - - /** * Hides the current input method if one is showing. */ void hideCurrentInputMethod(); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 17303478fa50..73601d968040 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -444,8 +444,7 @@ interface IWindowManager WindowContentFrameStats getWindowContentFrameStats(IBinder token); /** - * @return the dock side the current docked stack is at; must be one of the - * WindowManagerGlobal.DOCKED_* values + * This is a no-op. */ @UnsupportedAppUsage int getDockedStackSide(); @@ -457,27 +456,11 @@ interface IWindowManager void setDockedStackDividerTouchRegion(in Rect touchableRegion); /** - * Registers a listener that will be called when the dock divider changes its visibility or when - * the docked stack gets added/removed. - */ - @UnsupportedAppUsage - void registerDockedStackListener(IDockedStackListener listener); - - /** * Registers a listener that will be called when the pinned stack state changes. */ void registerPinnedStackListener(int displayId, IPinnedStackListener listener); /** - * Updates the dim layer used while resizing. - * - * @param visible Whether the dim layer should be visible. - * @param targetWindowingMode The windowing mode of the stack the dim layer should be placed on. - * @param alpha The translucency of the dim layer, between 0 and 1. - */ - void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha); - - /** * Requests Keyboard Shortcuts from the displayed window. * * @param receiver The receiver to deliver the results to. diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index 67e88a5a1831..74fac2b40472 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -197,6 +197,26 @@ public final class ImeFocusController { } /** + * Called by {@link ViewRootImpl} to feedback the state of the screen for this view. + * @param newScreenState The new state of the screen. Can be either + * {@link View#SCREEN_STATE_ON} or {@link View#SCREEN_STATE_OFF} + */ + @UiThread + void onScreenStateChanged(int newScreenState) { + if (!getImmDelegate().isCurrentRootView(mViewRootImpl)) { + return; + } + // Close input connection and IME when the screen is turn off for security concern. + if (newScreenState == View.SCREEN_STATE_OFF && mServedView != null) { + if (DEBUG) { + Log.d(TAG, "onScreenStateChanged, disconnect input when screen turned off"); + } + mNextServedView = null; + mViewRootImpl.dispatchCheckFocus(); + } + } + + /** * @param windowAttribute {@link WindowManager.LayoutParams} to be checked. * @return Whether the window is in local focus mode or not. */ diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index f2263693897b..35286ba007c4 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -16,8 +16,9 @@ package android.view; +import static android.view.InsetsController.ANIMATION_TYPE_USER; +import static android.view.InsetsController.AnimationType; import static android.view.InsetsState.ITYPE_IME; -import static android.view.InsetsState.toPublicType; import android.annotation.Nullable; import android.inputmethodservice.InputMethodService; @@ -99,6 +100,21 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } } + @Override + void hide(boolean animationFinished, @AnimationType int animationType) { + super.hide(); + + if (!animationFinished) { + if (animationType == ANIMATION_TYPE_USER) { + // if controlWindowInsetsAnimation is hiding keyboard. + notifyHidden(); + } + } else { + // remove IME surface as IME has finished hide animation. + removeSurface(); + } + } + /** * Request {@link InputMethodManager} to show the IME. * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}. @@ -110,7 +126,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { // If we had a request before to show from IME (tracked with mImeRequestedShow), reaching // this code here means that we now got control, so we can start the animation immediately. - if (fromIme || mImeRequestedShow) { + // If client window is trying to control IME and IME is already visible, it is immediate. + if (fromIme || mImeRequestedShow || mState.getSource(getType()).isVisible()) { mImeRequestedShow = false; return ShowResult.SHOW_IMMEDIATELY; } @@ -128,6 +145,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } @Override + public void removeSurface() { + getImm().removeImeSurface(); + } + + @Override public void setControl(@Nullable InsetsSourceControl control, int[] showTypes, int[] hideTypes) { super.setControl(control, showTypes, hideTypes); diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java index 5f9c4801ee66..cb9e746543f6 100644 --- a/core/java/android/view/InputEvent.java +++ b/core/java/android/view/InputEvent.java @@ -233,6 +233,21 @@ public abstract class InputEvent implements Parcelable { return mSeq; } + /** + * Gets the ID of this event. This is generated when an event is created and preserved until its + * last stage. It won't change just because the event crosses process boundary, but should + * change when making a copy with modifications. + * <p> + * To avoid exposing app usage to other processes this ID is generated from a CSPRNG. Therefore + * there isn't 100% guarantee on the uniqueness of this ID, though the chance of ID collisions + * is considerably low. The rule of thumb is not to rely on the uniqueness for production logic, + * but a good source for tracking an event (e.g. logging and profiling). + * + * @return The ID of this event. + * @hide + */ + public abstract int getId(); + public int describeContents() { return 0; } diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 0e037c24a85b..9247f4a29bdd 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.view.InsetsController.AnimationType; import static android.view.InsetsState.ISIDE_BOTTOM; import static android.view.InsetsState.ISIDE_FLOATING; import static android.view.InsetsState.ISIDE_LEFT; @@ -64,10 +65,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll private final Insets mShownInsets; private final Matrix mTmpMatrix = new Matrix(); private final InsetsState mInitialInsetsState; + private final @AnimationType int mAnimationType; private final @InsetsType int mTypes; private final InsetsAnimationControlCallbacks mController; private final WindowInsetsAnimation mAnimation; - private final Rect mFrame; private final boolean mFade; private Insets mCurrentInsets; private Insets mPendingInsets; @@ -83,7 +84,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll InsetsState state, WindowInsetsAnimationControlListener listener, @InsetsType int types, InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator, - boolean fade, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { + boolean fade, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation, + @AnimationType int animationType) { mControls = controls; mListener = listener; mTypes = types; @@ -96,12 +98,12 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll null /* typeSideMap */); mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */, mTypeSideMap); - mFrame = new Rect(frame); buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls); mAnimation = new WindowInsetsAnimation(mTypes, interpolator, durationMs); mAnimation.setAlpha(getCurrentAlpha()); + mAnimationType = animationType; mController.startAnimation(this, listener, types, mAnimation, new Bounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation); } @@ -135,6 +137,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll return InsetsState.toInternalType(mTypes).contains(type); } + @AnimationType int getAnimationType() { + return mAnimationType; + } + @Override public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) { if (mFinished) { diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 4a6a5a0312af..4cb8e1388858 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -582,7 +582,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls, frame, mState, listener, typesReady, this, durationMs, interpolator, fade, - layoutInsetsDuringAnimation); + layoutInsetsDuringAnimation, animationType); mRunningAnimations.add(new RunningAnimation(controller, animationType)); mRunningInsetsAnimations.add(controller.getAnimation()); cancellationSignal.setOnCancelListener(controller::onCancelled); @@ -598,7 +598,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation int typesReady = 0; boolean imeReady = true; for (int i = internalTypes.size() - 1; i >= 0; i--) { - InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); + final InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); boolean show = animationType == ANIMATION_TYPE_SHOW || animationType == ANIMATION_TYPE_USER; boolean canRun = false; @@ -694,7 +694,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (shown) { showDirectly(controller.getTypes()); } else { - hideDirectly(controller.getTypes()); + hideDirectly(controller.getTypes(), true /* animationFinished */, + controller.getAnimationType()); } } @@ -852,10 +853,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN); } - private void hideDirectly(@InsetsType int types) { + private void hideDirectly( + @InsetsType int types, boolean animationFinished, @AnimationType int animationType) { final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); for (int i = internalTypes.size() - 1; i >= 0; i--) { - getSourceConsumer(internalTypes.valueAt(i)).hide(); + getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType); } } @@ -887,8 +889,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (layoutDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) { showDirectly(types); } else { - hideDirectly(types); + hideDirectly(types, false /* animationFinished */, controller.getAnimationType()); } + if (mViewRoot.mView == null) { return; } diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java index 6caa4fed6409..719f649cb5a2 100644 --- a/core/java/android/view/InsetsSource.java +++ b/core/java/android/view/InsetsSource.java @@ -58,6 +58,10 @@ public class InsetsSource implements Parcelable { : null; } + public void setFrame(int left, int top, int right, int bottom) { + mFrame.set(left, top, right, bottom); + } + public void setFrame(Rect frame) { mFrame.set(frame); } diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index e6497c00c8dd..6d07a13091bd 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -16,12 +16,11 @@ package android.view; -import static android.view.InsetsController.ANIMATION_TYPE_NONE; +import static android.view.InsetsController.AnimationType; import static android.view.InsetsState.toPublicType; import android.annotation.IntDef; import android.annotation.Nullable; -import android.util.MutableShort; import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; @@ -59,9 +58,10 @@ public class InsetsSourceConsumer { protected final InsetsController mController; protected boolean mRequestedVisible; + protected final InsetsState mState; + protected final @InternalInsetsType int mType; + private final Supplier<Transaction> mTransactionSupplier; - private final @InternalInsetsType int mType; - private final InsetsState mState; private @Nullable InsetsSourceControl mSourceControl; private boolean mHasWindowFocus; @@ -137,6 +137,10 @@ public class InsetsSourceConsumer { setRequestedVisible(false); } + void hide(boolean animationFinished, @AnimationType int animationType) { + hide(); + } + /** * Called when current window gains focus */ @@ -201,6 +205,13 @@ public class InsetsSourceConsumer { } /** + * Remove surface on which this consumer type is drawn. + */ + public void removeSurface() { + // no-op for types that always return ShowResult#SHOW_IMMEDIATELY. + } + + /** * Sets requested visibility from the client, regardless of whether we are able to control it at * the moment. */ diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 8648682aaa2e..c877c454be91 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -24,6 +24,7 @@ import static android.view.ViewRootImpl.sNewInsetsMode; import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES; import static android.view.WindowInsets.Type.SIZE; import static android.view.WindowInsets.Type.SYSTEM_GESTURES; +import static android.view.WindowInsets.Type.displayCutout; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.indexOf; import static android.view.WindowInsets.Type.isVisibleInsetsType; @@ -71,6 +72,10 @@ public class InsetsState implements Parcelable { ITYPE_RIGHT_GESTURES, ITYPE_TOP_TAPPABLE_ELEMENT, ITYPE_BOTTOM_TAPPABLE_ELEMENT, + ITYPE_LEFT_DISPLAY_CUTOUT, + ITYPE_TOP_DISPLAY_CUTOUT, + ITYPE_RIGHT_DISPLAY_CUTOUT, + ITYPE_BOTTOM_DISPLAY_CUTOUT, ITYPE_IME }) public @interface InternalInsetsType {} @@ -88,8 +93,13 @@ public class InsetsState implements Parcelable { public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 7; public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 8; + public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 9; + public static final int ITYPE_TOP_DISPLAY_CUTOUT = 10; + public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 11; + public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 12; + /** Input method window. */ - public static final int ITYPE_IME = 9; + public static final int ITYPE_IME = 13; static final int LAST_TYPE = ITYPE_IME; @@ -185,8 +195,8 @@ public class InsetsState implements Parcelable { final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST; return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound, alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE - ? systemBars() | ime() - : systemBars(), + ? systemBars() | displayCutout() | ime() + : systemBars() | displayCutout(), sNewInsetsMode == NEW_INSETS_MODE_FULL && (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0); } @@ -358,6 +368,12 @@ public class InsetsState implements Parcelable { if ((types & Type.CAPTION_BAR) != 0) { result.add(ITYPE_CAPTION_BAR); } + if ((types & Type.DISPLAY_CUTOUT) != 0) { + result.add(ITYPE_LEFT_DISPLAY_CUTOUT); + result.add(ITYPE_TOP_DISPLAY_CUTOUT); + result.add(ITYPE_RIGHT_DISPLAY_CUTOUT); + result.add(ITYPE_BOTTOM_DISPLAY_CUTOUT); + } if ((types & Type.IME) != 0) { result.add(ITYPE_IME); } @@ -388,6 +404,11 @@ public class InsetsState implements Parcelable { case ITYPE_TOP_TAPPABLE_ELEMENT: case ITYPE_BOTTOM_TAPPABLE_ELEMENT: return Type.TAPPABLE_ELEMENT; + case ITYPE_LEFT_DISPLAY_CUTOUT: + case ITYPE_TOP_DISPLAY_CUTOUT: + case ITYPE_RIGHT_DISPLAY_CUTOUT: + case ITYPE_BOTTOM_DISPLAY_CUTOUT: + return Type.DISPLAY_CUTOUT; default: throw new IllegalArgumentException("Unknown type: " + type); } @@ -437,6 +458,14 @@ public class InsetsState implements Parcelable { return "ITYPE_TOP_TAPPABLE_ELEMENT"; case ITYPE_BOTTOM_TAPPABLE_ELEMENT: return "ITYPE_BOTTOM_TAPPABLE_ELEMENT"; + case ITYPE_LEFT_DISPLAY_CUTOUT: + return "ITYPE_LEFT_DISPLAY_CUTOUT"; + case ITYPE_TOP_DISPLAY_CUTOUT: + return "ITYPE_TOP_DISPLAY_CUTOUT"; + case ITYPE_RIGHT_DISPLAY_CUTOUT: + return "ITYPE_RIGHT_DISPLAY_CUTOUT"; + case ITYPE_BOTTOM_DISPLAY_CUTOUT: + return "ITYPE_BOTTOM_DISPLAY_CUTOUT"; case ITYPE_IME: return "ITYPE_IME"; default: diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 235f5e1dc970..e249c777caf6 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -1265,6 +1265,7 @@ public class KeyEvent extends InputEvent implements Parcelable { private KeyEvent mNext; + private int mId; @UnsupportedAppUsage private int mDeviceId; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) @@ -1350,9 +1351,9 @@ public class KeyEvent extends InputEvent implements Parcelable { private static native String nativeKeyCodeToString(int keyCode); private static native int nativeKeyCodeFromString(String keyCode); + private static native int nativeNextId(); - private KeyEvent() { - } + private KeyEvent() {} /** * Create a new key event. @@ -1362,6 +1363,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * @param code The key code. */ public KeyEvent(int action, int code) { + mId = nativeNextId(); mAction = action; mKeyCode = code; mRepeatCount = 0; @@ -1383,6 +1385,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public KeyEvent(long downTime, long eventTime, int action, int code, int repeat) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1407,6 +1410,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1435,6 +1439,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1465,6 +1470,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode, int flags) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1497,6 +1503,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public KeyEvent(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode, int flags, int source) { + mId = nativeNextId(); mDownTime = downTime; mEventTime = eventTime; mAction = action; @@ -1523,6 +1530,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * @param flags The flags for this key event */ public KeyEvent(long time, String characters, int deviceId, int flags) { + mId = nativeNextId(); mDownTime = time; mEventTime = time; mCharacters = characters; @@ -1539,6 +1547,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * Make an exact copy of an existing key event. */ public KeyEvent(KeyEvent origEvent) { + mId = origEvent.mId; mDownTime = origEvent.mDownTime; mEventTime = origEvent.mEventTime; mAction = origEvent.mAction; @@ -1567,6 +1576,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ @Deprecated public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) { + mId = nativeNextId(); // Not an exact copy so assign a new ID. mDownTime = origEvent.mDownTime; mEventTime = eventTime; mAction = origEvent.mAction; @@ -1598,15 +1608,16 @@ public class KeyEvent extends InputEvent implements Parcelable { } /** - * Obtains a (potentially recycled) key event. + * Obtains a (potentially recycled) key event. Used by native code to create a Java object. * * @hide */ - public static KeyEvent obtain(long downTime, long eventTime, int action, + public static KeyEvent obtain(int id, long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode, int flags, int source, int displayId, @Nullable byte[] hmac, String characters) { KeyEvent ev = obtain(); + ev.mId = id; ev.mDownTime = downTime; ev.mEventTime = eventTime; ev.mAction = action; @@ -1628,12 +1639,24 @@ public class KeyEvent extends InputEvent implements Parcelable { * * @hide */ + public static KeyEvent obtain(long downTime, long eventTime, int action, + int code, int repeat, int metaState, + int deviceId, int scanCode, int flags, int source, int displayId, String characters) { + return obtain(nativeNextId(), downTime, eventTime, action, code, repeat, metaState, + deviceId, scanCode, flags, source, displayId, null /* hmac */, characters); + } + + /** + * Obtains a (potentially recycled) key event. + * + * @hide + */ @UnsupportedAppUsage public static KeyEvent obtain(long downTime, long eventTime, int action, int code, int repeat, int metaState, int deviceId, int scancode, int flags, int source, String characters) { return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode, - flags, source, INVALID_DISPLAY, null /* hmac */, characters); + flags, source, INVALID_DISPLAY, characters); } /** @@ -1645,6 +1668,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public static KeyEvent obtain(KeyEvent other) { KeyEvent ev = obtain(); + ev.mId = other.mId; ev.mDownTime = other.mDownTime; ev.mEventTime = other.mEventTime; ev.mAction = other.mAction; @@ -1695,6 +1719,12 @@ public class KeyEvent extends InputEvent implements Parcelable { // Do nothing. } + /** @hide */ + @Override + public int getId() { + return mId; + } + /** * Create a new key event that is the same as the given one, but whose * event time and repeat count are replaced with the given value. @@ -1723,6 +1753,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime, int newRepeat, int newFlags) { KeyEvent ret = new KeyEvent(event); + ret.mId = nativeNextId(); // Not an exact copy so assign a new ID. ret.mEventTime = eventTime; ret.mRepeatCount = newRepeat; ret.mFlags = newFlags; @@ -1736,6 +1767,7 @@ public class KeyEvent extends InputEvent implements Parcelable { * @param action The new action code of the event. */ private KeyEvent(KeyEvent origEvent, int action) { + mId = nativeNextId(); // Not an exact copy so assign a new ID. mDownTime = origEvent.mDownTime; mEventTime = origEvent.mEventTime; mAction = action; @@ -1772,6 +1804,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public static KeyEvent changeFlags(KeyEvent event, int flags) { event = new KeyEvent(event); + event.mId = nativeNextId(); // Not an exact copy so assign a new ID. event.mFlags = flags; return event; } @@ -3095,6 +3128,7 @@ public class KeyEvent extends InputEvent implements Parcelable { } private KeyEvent(Parcel in) { + mId = in.readInt(); mDeviceId = in.readInt(); mSource = in.readInt(); mDisplayId = in.readInt(); @@ -3114,6 +3148,7 @@ public class KeyEvent extends InputEvent implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(PARCEL_TOKEN_KEY_EVENT); + out.writeInt(mId); out.writeInt(mDeviceId); out.writeInt(mSource); out.writeInt(mDisplayId); diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 006847656cac..19eff72ca814 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1550,6 +1550,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { private static native long nativeCopy(long destNativePtr, long sourceNativePtr, boolean keepHistory); @CriticalNative + private static native int nativeGetId(long nativePtr); + @CriticalNative private static native int nativeGetDeviceId(long nativePtr); @CriticalNative private static native int nativeGetSource(long nativePtr); @@ -2024,6 +2026,12 @@ public final class MotionEvent extends InputEvent implements Parcelable { } } + /** @hide */ + @Override + public int getId() { + return nativeGetId(mNativePtr); + } + /** {@inheritDoc} */ @Override public final int getDeviceId() { diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 0816e8433e66..e9f10c190c0a 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -1304,6 +1304,11 @@ public final class SurfaceControl implements Parcelable { * @hide */ public static final class DisplayConfig { + /** + * Invalid display config id. + */ + public static final int INVALID_DISPLAY_CONFIG_ID = -1; + public int width; public int height; public float xDpi; @@ -1313,6 +1318,14 @@ public final class SurfaceControl implements Parcelable { public long appVsyncOffsetNanos; public long presentationDeadlineNanos; + /** + * The config group ID this config is associated to. + * Configs in the same group are similar from vendor's perspective and switching between + * configs within the same group can be done seamlessly in most cases. + * @see: android.hardware.graphics.composer@2.4::IComposerClient::Attribute::CONFIG_GROUP + */ + public int configGroup; + @Override public String toString() { return "DisplayConfig{width=" + width @@ -1321,7 +1334,8 @@ public final class SurfaceControl implements Parcelable { + ", yDpi=" + yDpi + ", refreshRate=" + refreshRate + ", appVsyncOffsetNanos=" + appVsyncOffsetNanos - + ", presentationDeadlineNanos=" + presentationDeadlineNanos + "}"; + + ", presentationDeadlineNanos=" + presentationDeadlineNanos + + ", configGroup=" + configGroup + "}"; } } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 4badede2b093..a3b3f1f72310 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -201,7 +201,7 @@ public class SurfaceControlViewHost { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT); - relayout(width, height); + relayout(lp); } /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 11ab5724d927..53e8b527e928 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -11468,7 +11468,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, outLocalInsets.setEmpty(); return in; } - Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(in); + Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); outLocalInsets.set(result.first.toRect()); return result.second; } else { @@ -29794,7 +29794,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // accessibility CharSequence contentDescription = getContentDescription(); - stream.addProperty("accessibility:contentDescription", + stream.addUserProperty("accessibility:contentDescription", contentDescription == null ? "" : contentDescription.toString()); stream.addProperty("accessibility:labelFor", getLabelFor()); stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 2f44fe039cf5..8a5be75b6c31 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -1209,6 +1209,7 @@ public class ViewDebug { ByteArrayOutputStream baOut = new ByteArrayOutputStream(); final ViewHierarchyEncoder encoder = new ViewHierarchyEncoder(baOut); + encoder.setUserPropertiesEnabled(false); encoder.addProperty("window:left", view.mAttachInfo.mWindowLeft); encoder.addProperty("window:top", view.mAttachInfo.mWindowTop); view.encode(encoder); diff --git a/core/java/android/view/ViewHierarchyEncoder.java b/core/java/android/view/ViewHierarchyEncoder.java index b0e0524a0d85..ace05a6b6bf9 100644 --- a/core/java/android/view/ViewHierarchyEncoder.java +++ b/core/java/android/view/ViewHierarchyEncoder.java @@ -66,10 +66,16 @@ public class ViewHierarchyEncoder { private short mPropertyId = 1; private Charset mCharset = Charset.forName("utf-8"); + private boolean mUserPropertiesEnabled = true; + public ViewHierarchyEncoder(@NonNull ByteArrayOutputStream stream) { mStream = new DataOutputStream(stream); } + public void setUserPropertiesEnabled(boolean enabled) { + mUserPropertiesEnabled = enabled; + } + public void beginObject(@NonNull Object o) { startPropertyMap(); addProperty("meta:__name__", o.getClass().getName()); @@ -121,6 +127,17 @@ public class ViewHierarchyEncoder { } /** + * Encodes a user defined property if they are allowed to be encoded + * + * @see #setUserPropertiesEnabled(boolean) + */ + public void addUserProperty(@NonNull String name, @Nullable String s) { + if (mUserPropertiesEnabled) { + addProperty(name, s); + } + } + + /** * Writes the given name as the property name, and leaves it to the callee * to fill in value for this property. */ diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4a093e6038b8..36257d9f5fd9 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -52,8 +52,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CO import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; @@ -1445,6 +1443,7 @@ public final class ViewRootImpl implements ViewParent, final int newScreenState = toViewScreenState(newDisplayState); if (oldScreenState != newScreenState) { mView.dispatchScreenStateChanged(newScreenState); + mImeFocusController.onScreenStateChanged(newScreenState); } if (oldDisplayState == Display.STATE_OFF) { // Draw was suppressed so we need to for it to happen here. @@ -2008,7 +2007,6 @@ public final class ViewRootImpl implements ViewParent, final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility; final int flags = inOutParams.flags; final int type = inOutParams.type; - final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST; if ((inOutParams.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { inOutParams.insetsFlags.appearance = 0; @@ -2053,8 +2051,7 @@ public final class ViewRootImpl implements ViewParent, } if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) { ignoreVis = true; - } else if ((types & Type.systemBars()) == Type.systemBars() - && adjust == SOFT_INPUT_ADJUST_RESIZE) { + } else if ((types & Type.systemBars()) == Type.systemBars()) { types |= Type.ime(); } inOutParams.setFitInsetsTypes(types); @@ -2260,7 +2257,8 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mVisibleInsets.set(visibleInsets); } - InsetsController getInsetsController() { + @VisibleForTesting + public InsetsController getInsetsController() { return mInsetsController; } @@ -5379,7 +5377,8 @@ public final class ViewRootImpl implements ViewParent, if (mTracePrefix == null) { mTracePrefix = getClass().getSimpleName(); } - Trace.traceBegin(traceTag, mTracePrefix + " seq#=" + q.mEvent.getSequenceNumber()); + Trace.traceBegin(traceTag, mTracePrefix + " id=0x" + + Integer.toHexString(q.mEvent.getId())); } } @@ -7986,12 +7985,13 @@ public final class ViewRootImpl implements ViewParent, private void deliverInputEvent(QueuedInputEvent q) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", - q.mEvent.getSequenceNumber()); + q.mEvent.getId()); if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x" + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano=" - + q.mEvent.getEventTimeNano() + " seq#=" + q.mEvent.getSequenceNumber()); + + q.mEvent.getEventTimeNano() + " id=0x" + + Integer.toHexString(q.mEvent.getId())); } try { if (mInputEventConsistencyVerifier != null) { @@ -8032,7 +8032,7 @@ public final class ViewRootImpl implements ViewParent, private void finishInputEvent(QueuedInputEvent q) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent", - q.mEvent.getSequenceNumber()); + q.mEvent.getId()); if (q.mReceiver != null) { boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 4b284dbf9ed4..000fd8069292 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -712,13 +712,14 @@ public abstract class Window { * {@link View#setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener)} through the view * hierarchy. * + * @param view The view for which to apply insets. Must not be directly modified. * @param insets The root level insets that are about to be dispatched * @return A pair, with the first element containing the insets to apply as margin to the * root-level content views, and the second element determining what should be * dispatched to the content view. */ @NonNull - Pair<Insets, WindowInsets> onContentApplyWindowInsets( + Pair<Insets, WindowInsets> onContentApplyWindowInsets(@NonNull View view, @NonNull WindowInsets insets); } diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index a6c311e1daa5..20fa5cab0464 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -17,6 +17,7 @@ package android.view; +import static android.view.WindowInsets.Type.DISPLAY_CUTOUT; import static android.view.WindowInsets.Type.FIRST; import static android.view.WindowInsets.Type.IME; import static android.view.WindowInsets.Type.LAST; @@ -1209,6 +1210,13 @@ public final class WindowInsets { @NonNull public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) { mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT; + if (!mDisplayCutout.isEmpty()) { + final Insets safeInsets = Insets.of(mDisplayCutout.getSafeInsets()); + final int index = indexOf(DISPLAY_CUTOUT); + mTypeInsetsMap[index] = safeInsets; + mTypeMaxInsetsMap[index] = safeInsets; + mTypeVisibilityMap[index] = true; + } return this; } @@ -1256,8 +1264,10 @@ public final class WindowInsets { static final int MANDATORY_SYSTEM_GESTURES = 1 << 5; static final int TAPPABLE_ELEMENT = 1 << 6; - static final int LAST = 1 << 7; - static final int SIZE = 8; + static final int DISPLAY_CUTOUT = 1 << 7; + + static final int LAST = 1 << 8; + static final int SIZE = 9; static final int WINDOW_DECOR = LAST; static int indexOf(@InsetsType int type) { @@ -1276,8 +1286,10 @@ public final class WindowInsets { return 5; case TAPPABLE_ELEMENT: return 6; - case WINDOW_DECOR: + case DISPLAY_CUTOUT: return 7; + case WINDOW_DECOR: + return 8; default: throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST," + " type=" + type); @@ -1290,7 +1302,7 @@ public final class WindowInsets { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, value = {STATUS_BARS, NAVIGATION_BARS, CAPTION_BAR, IME, WINDOW_DECOR, - SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT}) + SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT, DISPLAY_CUTOUT}) public @interface InsetsType { } @@ -1358,6 +1370,20 @@ public final class WindowInsets { } /** + * Returns an insets type representing the area that used by {@link DisplayCutout}. + * + * <p>This is equivalent to the safe insets on {@link #getDisplayCutout()}.</p> + * + * @see DisplayCutout#getSafeInsetLeft() + * @see DisplayCutout#getSafeInsetTop() + * @see DisplayCutout#getSafeInsetRight() + * @see DisplayCutout#getSafeInsetBottom() + */ + public static @InsetsType int displayCutout() { + return DISPLAY_CUTOUT; + } + + /** * @return All system bars. Includes {@link #statusBars()}, {@link #captionBar()} as well as * {@link #navigationBars()}, but not {@link #ime()}. */ diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index b4c87953567b..299ae2f0c55e 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -31,7 +31,9 @@ import android.os.SystemClock; import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; +import android.util.SparseLongArray; import android.view.Display; +import android.view.ViewConfiguration; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -89,6 +91,9 @@ public final class AccessibilityInteractionClient private static final long TIMEOUT_INTERACTION_MILLIS = 5000; + private static final long DISABLE_PREFETCHING_FOR_SCROLLING_MILLIS = + (long) (ViewConfiguration.getSendRecurringAccessibilityEventsInterval() * 1.5); + private static final Object sStaticLock = new Object(); private static final LongSparseArray<AccessibilityInteractionClient> sClients = @@ -97,6 +102,10 @@ public final class AccessibilityInteractionClient private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache = new SparseArray<>(); + /** List of timestamps which indicate the latest time an a11y service receives a scroll event + from a window, mapping from windowId -> timestamp. */ + private static final SparseLongArray sScrollingWindows = new SparseLongArray(); + private static AccessibilityCache sAccessibilityCache = new AccessibilityCache(new AccessibilityCache.AccessibilityNodeRefresher()); @@ -422,6 +431,14 @@ public final class AccessibilityInteractionClient Log.i(LOG_TAG, "Node cache miss for " + idToString(accessibilityWindowId, accessibilityNodeId)); } + } else { + // No need to prefech nodes in bypass cache case. + prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK; + } + // Skip prefetching if window is scrolling. + if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0 + && isWindowScrolling(accessibilityWindowId)) { + prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK; } final int interactionId = mInteractionIdCounter.getAndIncrement(); final long identityToken = Binder.clearCallingIdentity(); @@ -718,6 +735,18 @@ public final class AccessibilityInteractionClient } public void onAccessibilityEvent(AccessibilityEvent event) { + switch (event.getEventType()) { + case AccessibilityEvent.TYPE_VIEW_SCROLLED: + updateScrollingWindow(event.getWindowId(), SystemClock.uptimeMillis()); + break; + case AccessibilityEvent.TYPE_WINDOWS_CHANGED: + if (event.getWindowChanges() == AccessibilityEvent.WINDOWS_CHANGE_REMOVED) { + deleteScrollingWindow(event.getWindowId()); + } + break; + default: + break; + } sAccessibilityCache.onAccessibilityEvent(event); } @@ -986,4 +1015,48 @@ public final class AccessibilityInteractionClient Log.e(LOG_TAG, disconnectedCount + " Disconnected nodes."); } } + + /** + * Update scroll event timestamp of a given window. + * + * @param windowId The window id. + * @param uptimeMillis Device uptime millis. + */ + private void updateScrollingWindow(int windowId, long uptimeMillis) { + synchronized (sScrollingWindows) { + sScrollingWindows.put(windowId, uptimeMillis); + } + } + + /** + * Remove a window from the scrolling windows list. + * + * @param windowId The window id. + */ + private void deleteScrollingWindow(int windowId) { + synchronized (sScrollingWindows) { + sScrollingWindows.delete(windowId); + } + } + + /** + * Whether or not the window is scrolling. + * + * @param windowId + * @return true if it's scrolling. + */ + private boolean isWindowScrolling(int windowId) { + synchronized (sScrollingWindows) { + final long latestScrollingTime = sScrollingWindows.get(windowId); + if (latestScrollingTime == 0) { + return false; + } + final long currentUptime = SystemClock.uptimeMillis(); + if (currentUptime > (latestScrollingTime + DISABLE_PREFETCHING_FOR_SCROLLING_MILLIS)) { + sScrollingWindows.delete(windowId); + return false; + } + } + return true; + } } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index eb4f9db39e3e..9f83862774eb 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -138,6 +138,9 @@ public class AccessibilityNodeInfo implements Parcelable { public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004; /** @hide */ + public static final int FLAG_PREFETCH_MASK = 0x00000007; + + /** @hide */ public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008; /** @hide */ diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index 7f90d572ce89..6815509b6f2e 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -31,6 +31,7 @@ import android.text.InputType; import android.text.TextUtils; import android.util.Printer; import android.view.View; +import android.view.autofill.AutofillId; import com.android.internal.annotations.VisibleForTesting; @@ -425,6 +426,15 @@ public class EditorInfo implements InputType, Parcelable { public String packageName; /** + * Autofill Id for the field that's currently on focus. + * + * <p> Marked as hide since it's only used by framework.</p> + * @hide + */ + @NonNull + public AutofillId autofillId = new AutofillId(View.NO_ID); + + /** * Identifier for the editor's field. This is optional, and may be * 0. By default it is filled in with the result of * {@link android.view.View#getId() View.getId()} on the View that @@ -793,6 +803,7 @@ public class EditorInfo implements InputType, Parcelable { pw.println(prefix + "hintText=" + hintText + " label=" + label); pw.println(prefix + "packageName=" + packageName + + " autofillId=" + autofillId + " fieldId=" + fieldId + " fieldName=" + fieldName); pw.println(prefix + "extras=" + extras); @@ -821,6 +832,7 @@ public class EditorInfo implements InputType, Parcelable { TextUtils.writeToParcel(hintText, dest, flags); TextUtils.writeToParcel(label, dest, flags); dest.writeString(packageName); + autofillId.writeToParcel(dest, flags); dest.writeInt(fieldId); dest.writeString(fieldName); dest.writeBundle(extras); @@ -852,6 +864,7 @@ public class EditorInfo implements InputType, Parcelable { res.hintText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); res.label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); res.packageName = source.readString(); + res.autofillId = AutofillId.CREATOR.createFromParcel(source); res.fieldId = source.readInt(); res.fieldName = source.readString(); res.extras = source.readBundle(); diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java index 024de4de92e7..cb0320e966d1 100644 --- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java +++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java @@ -69,6 +69,9 @@ public final class InlineSuggestionInfo implements Parcelable { /** The type of the UI. */ private final @NonNull @Type String mType; + /** Whether the suggestion should be pinned or not. */ + private final boolean mPinned; + /** * Creates a new {@link InlineSuggestionInfo}, for testing purpose. * @@ -79,8 +82,8 @@ public final class InlineSuggestionInfo implements Parcelable { public static InlineSuggestionInfo newInlineSuggestionInfo( @NonNull InlinePresentationSpec presentationSpec, @NonNull @Source String source, - @Nullable String[] autofillHints) { - return new InlineSuggestionInfo(presentationSpec, source, autofillHints, TYPE_SUGGESTION); + @Nullable String[] autofillHints, @NonNull @Type String type, boolean isPinned) { + return new InlineSuggestionInfo(presentationSpec, source, autofillHints, type, isPinned); } @@ -127,6 +130,8 @@ public final class InlineSuggestionInfo implements Parcelable { * Hints for the type of data being suggested. * @param type * The type of the UI. + * @param pinned + * Whether the suggestion should be pinned or not. * @hide */ @DataClass.Generated.Member @@ -134,7 +139,8 @@ public final class InlineSuggestionInfo implements Parcelable { @NonNull InlinePresentationSpec presentationSpec, @NonNull @Source String source, @Nullable String[] autofillHints, - @NonNull @Type String type) { + @NonNull @Type String type, + boolean pinned) { this.mPresentationSpec = presentationSpec; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mPresentationSpec); @@ -163,6 +169,7 @@ public final class InlineSuggestionInfo implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mType); + this.mPinned = pinned; // onConstructed(); // You can define this method to get a callback } @@ -199,6 +206,14 @@ public final class InlineSuggestionInfo implements Parcelable { return mType; } + /** + * Whether the suggestion should be pinned or not. + */ + @DataClass.Generated.Member + public boolean isPinned() { + return mPinned; + } + @Override @DataClass.Generated.Member public String toString() { @@ -209,7 +224,8 @@ public final class InlineSuggestionInfo implements Parcelable { "presentationSpec = " + mPresentationSpec + ", " + "source = " + mSource + ", " + "autofillHints = " + java.util.Arrays.toString(mAutofillHints) + ", " + - "type = " + mType + + "type = " + mType + ", " + + "pinned = " + mPinned + " }"; } @@ -229,7 +245,8 @@ public final class InlineSuggestionInfo implements Parcelable { && java.util.Objects.equals(mPresentationSpec, that.mPresentationSpec) && java.util.Objects.equals(mSource, that.mSource) && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints) - && java.util.Objects.equals(mType, that.mType); + && java.util.Objects.equals(mType, that.mType) + && mPinned == that.mPinned; } @Override @@ -243,6 +260,7 @@ public final class InlineSuggestionInfo implements Parcelable { _hash = 31 * _hash + java.util.Objects.hashCode(mSource); _hash = 31 * _hash + java.util.Arrays.hashCode(mAutofillHints); _hash = 31 * _hash + java.util.Objects.hashCode(mType); + _hash = 31 * _hash + Boolean.hashCode(mPinned); return _hash; } @@ -253,6 +271,7 @@ public final class InlineSuggestionInfo implements Parcelable { // void parcelFieldName(Parcel dest, int flags) { ... } byte flg = 0; + if (mPinned) flg |= 0x10; if (mAutofillHints != null) flg |= 0x4; dest.writeByte(flg); dest.writeTypedObject(mPresentationSpec, flags); @@ -273,6 +292,7 @@ public final class InlineSuggestionInfo implements Parcelable { // static FieldType unparcelFieldName(Parcel in) { ... } byte flg = in.readByte(); + boolean pinned = (flg & 0x10) != 0; InlinePresentationSpec presentationSpec = (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR); String source = in.readString(); String[] autofillHints = (flg & 0x4) == 0 ? null : in.createStringArray(); @@ -306,6 +326,7 @@ public final class InlineSuggestionInfo implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mType); + this.mPinned = pinned; // onConstructed(); // You can define this method to get a callback } @@ -325,10 +346,10 @@ public final class InlineSuggestionInfo implements Parcelable { }; @DataClass.Generated( - time = 1579806757327L, + time = 1582753084046L, codegenVersion = "1.0.14", sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java", - inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[])\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)") + inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final boolean mPinned\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.view.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index 71c9e33d0eee..869a9295e16b 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -348,6 +348,27 @@ public interface InputMethod { * {@link InputMethodManager#RESULT_UNCHANGED_HIDDEN InputMethodManager.RESULT_UNCHANGED_HIDDEN}, * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}. + * @param hideInputToken an opaque {@link android.os.Binder} token to identify which API call + * of {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}} is associated + * with this callback. + * @hide + */ + @MainThread + public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver, + IBinder hideInputToken); + + /** + * Request that any soft input part of the input method be hidden from the user. + * @param flags Provides additional information about the show request. + * Currently always 0. + * @param resultReceiver The client requesting the show may wish to + * be told the impact of their request, which should be supplied here. + * The result code should be + * {@link InputMethodManager#RESULT_UNCHANGED_SHOWN InputMethodManager.RESULT_UNCHANGED_SHOWN}, + * {@link InputMethodManager#RESULT_UNCHANGED_HIDDEN + * InputMethodManager.RESULT_UNCHANGED_HIDDEN}, + * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or + * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}. */ @MainThread public void hideSoftInput(int flags, ResultReceiver resultReceiver); @@ -366,4 +387,13 @@ public interface InputMethod { * @hide */ public void setCurrentShowInputToken(IBinder showInputToken); + + /** + * Update token of the client window requesting {@link #hideSoftInput(int, ResultReceiver)} + * @param hideInputToken dummy app window token for window requesting + * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)} + * @hide + */ + public void setCurrentHideInputToken(IBinder hideInputToken); + } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 39d5f5c396a1..aca265b1f59a 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1709,7 +1709,7 @@ public final class InputMethodManager { } try { - return mService.hideSoftInput(mClient, flags, resultReceiver); + return mService.hideSoftInput(mClient, windowToken, flags, resultReceiver); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1858,6 +1858,7 @@ public final class InputMethodManager { // system can verify the consistency between the uid of this process and package name passed // from here. See comment of Context#getOpPackageName() for details. tba.packageName = view.getContext().getOpPackageName(); + tba.autofillId = view.getAutofillId(); tba.fieldId = view.getId(); InputConnection ic = view.onCreateInputConnection(tba); if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); @@ -1986,7 +1987,8 @@ public final class InputMethodManager { @UnsupportedAppUsage void closeCurrentInput() { try { - mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null); + mService.hideSoftInput( + mClient, mCurRootView.getView().getWindowToken(), HIDE_NOT_ALWAYS, null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2056,6 +2058,21 @@ public final class InputMethodManager { } /** + * Notify IME directly to remove surface as it is no longer visible. + * @hide + */ + public void removeImeSurface() { + synchronized (mH) { + try { + if (mCurMethod != null) { + mCurMethod.removeImeSurface(); + } + } catch (RemoteException re) { + } + } + } + + /** * Report the current selection range. * * <p><strong>Editor authors</strong>, you need to call this method whenever diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java index eb81628f9e27..0d688ffa44c8 100644 --- a/core/java/android/view/inputmethod/InputMethodSession.java +++ b/core/java/android/view/inputmethod/InputMethodSession.java @@ -191,4 +191,10 @@ public interface InputMethodSession { * @hide */ public void notifyImeHidden(); + + /** + * Notify IME directly to remove surface as it is no longer visible. + * @hide + */ + public void removeImeSurface(); } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 2d27a789ebcb..53541f786da0 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -369,10 +369,22 @@ public abstract class WebSettings { public abstract boolean getDisplayZoomControls(); /** - * Enables or disables file access within WebView. File access is enabled by - * default. Note that this enables or disables file system access only. - * Assets and resources are still accessible using file:///android_asset and - * file:///android_res. + * Enables or disables file access within WebView. + * Note that this enables or disables file system access only. Assets and resources + * are still accessible using file:///android_asset and file:///android_res. + * <p class="note"> + * <b>Note:</b> Apps should not open {@code file://} URLs from any external source in + * WebView, don't enable this if your app accepts arbitrary URLs from external sources. + * It's recommended to always use + * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader"> + * androidx.webkit.WebViewAssetLoader</a> to access files including assets and resources over + * {@code http(s)://} schemes, instead of {@code file://} URLs. To prevent possible security + * issues targeting {@link android.os.Build.VERSION_CODES#Q} and earlier, you should explicitly + * set this value to {@code false}. + * <p> + * The default value is {@code true} for apps targeting + * {@link android.os.Build.VERSION_CODES#Q} and below, and {@code false} when targeting + * {@link android.os.Build.VERSION_CODES#R} and above. */ public abstract void setAllowFileAccess(boolean allow); diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index a299b0185433..8ea824d3ce82 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -353,8 +353,9 @@ public final class Magnifier { // Gets the startX for new style, which should be bounded by the horizontal bounds. // Also calculates the left/right cut width for pixel copy. - leftBound += mViewCoordinatesInSurface[0]; - rightBound += mViewCoordinatesInSurface[0]; + leftBound = Math.max(leftBound + mViewCoordinatesInSurface[0], 0); + rightBound = Math.min( + rightBound + mViewCoordinatesInSurface[0], mContentCopySurface.mWidth); mLeftCutWidth = Math.max(0, leftBound - startX); mRightCutWidth = Math.max(0, startX + mSourceWidth - rightBound); startX = Math.max(startX, leftBound); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 815cc5cbb10d..f3243aaf5b7d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -13174,7 +13174,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener stream.addProperty("text:selectionStart", getSelectionStart()); stream.addProperty("text:selectionEnd", getSelectionEnd()); stream.addProperty("text:curTextColor", mCurTextColor); - stream.addProperty("text:text", mText == null ? null : mText.toString()); + stream.addUserProperty("text:text", mText == null ? null : mText.toString()); stream.addProperty("text:gravity", mGravity); } diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 9e4ebfe44b58..7d97a91b7435 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -31,9 +31,7 @@ import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.PixelFormat; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -43,11 +41,8 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import com.android.internal.annotations.GuardedBy; @@ -122,6 +117,7 @@ public class Toast { private final Binder mToken; private final Context mContext; private final Handler mHandler; + private final ToastPresenter mPresenter; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) final TN mTN; @UnsupportedAppUsage @@ -172,7 +168,8 @@ public class Toast { looper = getLooper(looper); mHandler = new Handler(looper); mCallbacks = new ArrayList<>(); - mTN = new TN(context.getPackageName(), mToken, mCallbacks, looper); + mPresenter = new ToastPresenter(context, AccessibilityManager.getInstance(context)); + mTN = new TN(mPresenter, context.getPackageName(), mToken, mCallbacks, looper); mTN.mY = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.toast_y_offset); mTN.mGravity = context.getResources().getInteger( @@ -504,13 +501,7 @@ public class Toast { return result; } else { Toast result = new Toast(context, looper); - - LayoutInflater inflate = (LayoutInflater) - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); - TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message); - tv.setText(text); - + View v = result.mPresenter.getTextToastView(text); result.mNextView = v; result.mDuration = duration; @@ -611,34 +602,20 @@ public class Toast { final String mPackageName; final Binder mToken; + private final ToastPresenter mPresenter; @GuardedBy("mCallbacks") private final List<Callback> mCallbacks; - static final long SHORT_DURATION_TIMEOUT = 4000; - static final long LONG_DURATION_TIMEOUT = 7000; - /** * Creates a {@link ITransientNotification} object. * * The parameter {@code callbacks} is not copied and is accessed with itself as its own * lock. */ - TN(String packageName, Binder token, List<Callback> callbacks, @Nullable Looper looper) { - // XXX This should be changed to use a Dialog, with a Theme.Toast - // defined that sets up the layout params appropriately. - final WindowManager.LayoutParams params = mParams; - params.height = WindowManager.LayoutParams.WRAP_CONTENT; - params.width = WindowManager.LayoutParams.WRAP_CONTENT; - params.format = PixelFormat.TRANSLUCENT; - params.windowAnimations = com.android.internal.R.style.Animation_Toast; - params.type = WindowManager.LayoutParams.TYPE_TOAST; - params.setFitInsetsIgnoringVisibility(true); - params.setTitle("Toast"); - params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; - + TN(ToastPresenter presenter, String packageName, Binder token, List<Callback> callbacks, + @Nullable Looper looper) { + mPresenter = presenter; mPackageName = packageName; mToken = token; mCallbacks = callbacks; @@ -673,6 +650,8 @@ public class Toast { } } }; + + presenter.startLayoutParams(mParams, packageName); } private List<Callback> getCallbacks() { @@ -718,30 +697,12 @@ public class Toast { handleHide(); mView = mNextView; Context context = mView.getContext().getApplicationContext(); - String packageName = mView.getContext().getOpPackageName(); if (context == null) { context = mView.getContext(); } - mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); - // We can resolve the Gravity here by using the Locale for getting - // the layout direction - final Configuration config = mView.getContext().getResources().getConfiguration(); - final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection()); - mParams.gravity = gravity; - if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { - mParams.horizontalWeight = 1.0f; - } - if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { - mParams.verticalWeight = 1.0f; - } - mParams.x = mX; - mParams.y = mY; - mParams.verticalMargin = mVerticalMargin; - mParams.horizontalMargin = mHorizontalMargin; - mParams.packageName = packageName; - mParams.hideTimeoutMilliseconds = mDuration == - Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; - mParams.token = windowToken; + mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + mPresenter.adjustLayoutParams(mParams, windowToken, mDuration, mGravity, mX, mY, + mHorizontalMargin, mVerticalMargin); if (mView.getParent() != null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); @@ -753,7 +714,7 @@ public class Toast { // invalidated. Let us hedge against that. try { mWM.addView(mView, mParams); - trySendAccessibilityEvent(); + mPresenter.trySendAccessibilityEvent(mView, mPackageName); for (Callback callback : getCallbacks()) { callback.onToastShown(); } @@ -763,22 +724,6 @@ public class Toast { } } - private void trySendAccessibilityEvent() { - AccessibilityManager accessibilityManager = - AccessibilityManager.getInstance(mView.getContext()); - if (!accessibilityManager.isEnabled()) { - return; - } - // treat toasts as notifications since they are used to - // announce a transient piece of information to the user - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); - event.setClassName(getClass().getName()); - event.setPackageName(mView.getContext().getPackageName()); - mView.dispatchPopulateAccessibilityEvent(event); - accessibilityManager.sendAccessibilityEvent(event); - } - @UnsupportedAppUsage public void handleHide() { if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView); diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java new file mode 100644 index 000000000000..0447b6bb9f11 --- /dev/null +++ b/core/java/android/widget/ToastPresenter.java @@ -0,0 +1,148 @@ +/* + * 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.widget; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; + +import com.android.internal.R; +import com.android.internal.util.ArrayUtils; + +/** + * Class responsible for toast presentation inside app's process and in system UI. + * + * @hide + */ +public class ToastPresenter { + private static final long SHORT_DURATION_TIMEOUT = 4000; + private static final long LONG_DURATION_TIMEOUT = 7000; + + private final Context mContext; + private final Resources mResources; + private final AccessibilityManager mAccessibilityManager; + + public ToastPresenter(Context context, AccessibilityManager accessibilityManager) { + mContext = context; + mResources = context.getResources(); + mAccessibilityManager = accessibilityManager; + } + + /** + * Initializes {@code params} with default values for toasts. + */ + public void startLayoutParams(WindowManager.LayoutParams params, String packageName) { + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.width = WindowManager.LayoutParams.WRAP_CONTENT; + params.format = PixelFormat.TRANSLUCENT; + params.windowAnimations = R.style.Animation_Toast; + params.type = WindowManager.LayoutParams.TYPE_TOAST; + params.setFitInsetsIgnoringVisibility(true); + params.setTitle("Toast"); + params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + setShowForAllUsersIfApplicable(params, packageName); + } + + /** + * Customizes {@code params} according to other parameters, ready to be passed to {@link + * WindowManager#addView(View, ViewGroup.LayoutParams)}. + */ + public void adjustLayoutParams(WindowManager.LayoutParams params, IBinder windowToken, + int duration, int gravity, int xOffset, int yOffset, float horizontalMargin, + float verticalMargin) { + Configuration config = mResources.getConfiguration(); + int absGravity = Gravity.getAbsoluteGravity(gravity, config.getLayoutDirection()); + params.gravity = absGravity; + if ((absGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { + params.horizontalWeight = 1.0f; + } + if ((absGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { + params.verticalWeight = 1.0f; + } + params.x = xOffset; + params.y = yOffset; + params.horizontalMargin = horizontalMargin; + params.verticalMargin = verticalMargin; + params.packageName = mContext.getPackageName(); + params.hideTimeoutMilliseconds = + (duration == Toast.LENGTH_LONG) ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; + params.token = windowToken; + } + + /** + * Sets {@link WindowManager.LayoutParams#SYSTEM_FLAG_SHOW_FOR_ALL_USERS} flag if {@code + * packageName} is a cross-user package. + * + * Implementation note: + * This code is safe to be executed in SystemUI and the app's process: + * <li>SystemUI: It's running on a trusted domain so apps can't tamper with it. SystemUI + * has the permission INTERNAL_SYSTEM_WINDOW needed by the flag, so SystemUI can add + * the flag on behalf of those packages, which all contain INTERNAL_SYSTEM_WINDOW + * permission. + * <li>App: The flag being added is protected behind INTERNAL_SYSTEM_WINDOW permission + * and any app can already add that flag via getWindowParams() if it has that + * permission, so we are just doing this automatically for cross-user packages. + */ + private void setShowForAllUsersIfApplicable(WindowManager.LayoutParams params, + String packageName) { + if (isCrossUserPackage(packageName)) { + params.privateFlags = WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + } + } + + private boolean isCrossUserPackage(String packageName) { + String[] packages = mResources.getStringArray(R.array.config_toastCrossUserPackages); + return ArrayUtils.contains(packages, packageName); + } + + /** + * Returns the default text toast view for message {@code text}. + */ + public View getTextToastView(CharSequence text) { + View view = LayoutInflater.from(mContext).inflate( + R.layout.transient_notification, null); + TextView textView = view.findViewById(com.android.internal.R.id.message); + textView.setText(text); + return view; + } + + /** + * Sends {@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED} event if accessibility is + * enabled. + */ + public void trySendAccessibilityEvent(View view, String packageName) { + if (!mAccessibilityManager.isEnabled()) { + return; + } + AccessibilityEvent event = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); + event.setClassName(Toast.class.getName()); + event.setPackageName(packageName); + view.dispatchPopulateAccessibilityEvent(event); + mAccessibilityManager.sendAccessibilityEvent(event); + } +} diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index dc6942cdc2c3..6a0b443b7df8 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -71,8 +71,8 @@ interface IBatteryStats { void noteSyncStart(String name, int uid); void noteSyncFinish(String name, int uid); - void noteJobStart(String name, int uid, int standbyBucket, int jobid); - void noteJobFinish(String name, int uid, int stopReason, int standbyBucket, int jobid); + void noteJobStart(String name, int uid); + void noteJobFinish(String name, int uid, int stopReason); void noteStartWakelock(int uid, int pid, String name, String historyName, int type, boolean unimportantForLogging); diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 417e23f56448..71ee8af8b11a 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -33,7 +33,7 @@ import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; interface IVoiceInteractionManagerService { - void showSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags); + void showSession(in Bundle sessionArgs, int flags); boolean deliverNewSession(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor); boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags); @@ -52,68 +52,91 @@ interface IVoiceInteractionManagerService { /** * Gets the registered Sound model for keyphrase detection for the current user. * May be null if no matching sound model exists. + * Caller must either be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model + * enrollment application detected by + * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. * * @param keyphraseId The unique identifier for the keyphrase. * @param bcp47Locale The BCP47 language tag for the keyphrase's locale. + * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES */ @UnsupportedAppUsage SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, in String bcp47Locale); /** - * Add/Update the given keyphrase sound model. + * Add/Update the given keyphrase sound model for the current user. + * Caller must either be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model + * enrollment application detected by + * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. + * + * @param model The keyphrase sound model to store peristantly. + * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES */ int updateKeyphraseSoundModel(in SoundTrigger.KeyphraseSoundModel model); /** * Deletes the given keyphrase sound model for the current user. + * Caller must either be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model + * enrollment application detected by + * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. * * @param keyphraseId The unique identifier for the keyphrase. * @param bcp47Locale The BCP47 language tag for the keyphrase's locale. + * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES */ int deleteKeyphraseSoundModel(int keyphraseId, in String bcp47Locale); /** * Gets the properties of the DSP hardware on this device, null if not present. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. */ - SoundTrigger.ModuleProperties getDspModuleProperties(in IVoiceInteractionService service); + SoundTrigger.ModuleProperties getDspModuleProperties(); /** * Indicates if there's a keyphrase sound model available for the given keyphrase ID and the * user ID of the caller. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. * - * @param service The current VoiceInteractionService. * @param keyphraseId The unique identifier for the keyphrase. * @param bcp47Locale The BCP47 language tag for the keyphrase's locale. */ - boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, - String bcp47Locale); + boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale); /** * Generates KeyphraseMetadata for an enrolled sound model based on keyphrase string, locale, * and the user ID of the caller. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. * - * @param service The current VoiceInteractionService * @param keyphrase Keyphrase text associated with the enrolled model * @param bcp47Locale The BCP47 language tag for the keyphrase's locale. * @return The metadata for the enrolled voice model bassed on the passed in parameters. Null if * no matching voice model exists. */ - KeyphraseMetadata getEnrolledKeyphraseMetadata(IVoiceInteractionService service, - String keyphrase, String bcp47Locale); + KeyphraseMetadata getEnrolledKeyphraseMetadata(String keyphrase, String bcp47Locale); /** * Starts a recognition for the given keyphrase. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. */ - int startRecognition(in IVoiceInteractionService service, int keyphraseId, - in String bcp47Locale, in IRecognitionStatusCallback callback, + int startRecognition(int keyphraseId, in String bcp47Locale, + in IRecognitionStatusCallback callback, in SoundTrigger.RecognitionConfig recognitionConfig); /** * Stops a recognition for the given keyphrase. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. */ - int stopRecognition(in IVoiceInteractionService service, int keyphraseId, - in IRecognitionStatusCallback callback); + int stopRecognition(int keyphraseId, in IRecognitionStatusCallback callback); /** * Set a model specific ModelParams with the given value. This * parameter will keep its value for the duration the model is loaded regardless of starting and * stopping recognition. Once the model is unloaded, the value will be lost. * queryParameter should be checked first before calling this method. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. * - * @param service The current VoiceInteractionService. * @param keyphraseId The unique identifier for the keyphrase. * @param modelParam ModelParams * @param value Value to set @@ -123,36 +146,37 @@ interface IVoiceInteractionManagerService { * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or * if API is not supported by HAL */ - int setParameter(in IVoiceInteractionService service, int keyphraseId, - in ModelParams modelParam, int value); + int setParameter(int keyphraseId, in ModelParams modelParam, int value); /** * Get a model specific ModelParams. This parameter will keep its value * for the duration the model is loaded regardless of starting and stopping recognition. * Once the model is unloaded, the value will be lost. If the value is not set, a default * value is returned. See ModelParams for parameter default values. * queryParameter should be checked first before calling this method. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. * - * @param service The current VoiceInteractionService. * @param keyphraseId The unique identifier for the keyphrase. * @param modelParam ModelParams * @return value of parameter */ - int getParameter(in IVoiceInteractionService service, int keyphraseId, - in ModelParams modelParam); + int getParameter(int keyphraseId, in ModelParams modelParam); /** * Determine if parameter control is supported for the given model handle. * This method should be checked prior to calling setParameter or getParameter. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. * - * @param service The current VoiceInteractionService. * @param keyphraseId The unique identifier for the keyphrase. * @param modelParam ModelParams * @return supported range of parameter, null if not supported */ - @nullable SoundTrigger.ModelParamRange queryParameter(in IVoiceInteractionService service, - int keyphraseId, in ModelParams modelParam); + @nullable SoundTrigger.ModelParamRange queryParameter(int keyphraseId, + in ModelParams modelParam); /** * @return the component name for the currently active voice interaction service + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ ComponentName getActiveServiceComponentName(); @@ -164,59 +188,70 @@ interface IVoiceInteractionManagerService { * @param sourceFlags flags indicating the source of this show * @param showCallback optional callback to be notified when the session was shown * @param activityToken optional token of activity that needs to be on top + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ boolean showSessionForActiveService(in Bundle args, int sourceFlags, IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken); /** * Hides the session from the active service, if it is showing. + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ void hideCurrentSession(); /** * Notifies the active service that a launch was requested from the Keyguard. This will only * be called if {@link #activeServiceSupportsLaunchFromKeyguard()} returns true. + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ void launchVoiceAssistFromKeyguard(); /** * Indicates whether there is a voice session running (but not necessarily showing). + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ boolean isSessionRunning(); /** * Indicates whether the currently active voice interaction service is capable of handling the * assist gesture. + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ boolean activeServiceSupportsAssist(); /** * Indicates whether the currently active voice interaction service is capable of being launched * from the lockscreen. + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ boolean activeServiceSupportsLaunchFromKeyguard(); /** * Called when the lockscreen got shown. + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ void onLockscreenShown(); /** * Register a voice interaction listener. + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener); /** * Checks the availability of a set of voice actions for the current active voice service. * Returns all supported voice actions. + * @RequiresPermission Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE */ void getActiveServiceSupportedActions(in List<String> voiceActions, in IVoiceActionCheckCallback callback); /** * Provide hints for showing UI. + * Caller must be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. */ - void setUiHints(in IVoiceInteractionService service, in Bundle hints); + void setUiHints(in Bundle hints); /** * Requests a list of supported actions from a specific activity. diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index ef9b3d1021ef..73ef8c6f6fca 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -23,6 +23,7 @@ import android.content.ContentResolver; import android.content.Intent; import android.content.res.AssetFileDescriptor; import android.database.Cursor; +import android.database.DatabaseUtils; import android.database.MatrixCursor; import android.database.MatrixCursor.RowBuilder; import android.graphics.Point; @@ -38,6 +39,7 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsProvider; import android.provider.MediaStore; +import android.provider.MediaStore.Files.FileColumns; import android.provider.MetadataReader; import android.system.Int64Ref; import android.text.TextUtils; @@ -333,15 +335,17 @@ public abstract class FileSystemProvider extends DocumentsProvider { if (isDirectory) { FileUtils.deleteContents(file); } - if (!file.delete()) { + // We could be deleting pending media which doesn't have any content yet, so only throw + // if the file exists and we fail to delete it. + if (file.exists() && !file.delete()) { throw new IllegalStateException("Failed to delete " + file); } onDocIdChanged(docId); - removeFromMediaStore(visibleFile, isDirectory); + removeFromMediaStore(visibleFile); } - private void removeFromMediaStore(@Nullable File visibleFile, boolean isFolder) + private void removeFromMediaStore(@Nullable File visibleFile) throws FileNotFoundException { // visibleFolder is null if we're removing a document from external thumb drive or SD card. if (visibleFile != null) { @@ -350,21 +354,19 @@ public abstract class FileSystemProvider extends DocumentsProvider { try { final ContentResolver resolver = getContext().getContentResolver(); final Uri externalUri = MediaStore.Files.getContentUri("external"); - - // Remove media store entries for any files inside this directory, using - // path prefix match. Logic borrowed from MtpDatabase. - if (isFolder) { - final String path = visibleFile.getAbsolutePath() + "/"; - resolver.delete(externalUri, - "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)", - new String[]{path + "%", Integer.toString(path.length()), path}); - } - - // Remove media store entry for this exact file. - final String path = visibleFile.getAbsolutePath(); - resolver.delete(externalUri, - "_data LIKE ?1 AND lower(_data)=lower(?2)", - new String[]{path, path}); + final Bundle queryArgs = new Bundle(); + queryArgs.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_INCLUDE); + + // Remove the media store entry corresponding to visibleFile and if it is a + // directory, also remove media store entries for any files inside this directory. + // Logic borrowed from com.android.providers.media.scan.ModernMediaScanner. + final String pathEscapedForLike = DatabaseUtils.escapeForLike( + visibleFile.getAbsolutePath()); + ContentResolver.includeSqlSelectionArgs(queryArgs, + FileColumns.DATA + " LIKE ? ESCAPE '\\' OR " + + FileColumns.DATA + " LIKE ? ESCAPE '\\'", + new String[] {pathEscapedForLike + "/%", pathEscapedForLike}); + resolver.delete(externalUri, queryArgs); } finally { Binder.restoreCallingIdentity(token); } diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl index 20cd7c21d512..9a226860831a 100644 --- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl +++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl @@ -41,5 +41,5 @@ interface IInputMethodPrivilegedOperations { boolean shouldOfferSwitchingToNextInputMethod(); void notifyUserAction(); void reportPreRendered(in EditorInfo info); - void applyImeVisibility(IBinder showInputToken, boolean setVisible); + void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible); } diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java index 9eeef963de7f..e5475f8bea9d 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java +++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java @@ -371,18 +371,20 @@ public final class InputMethodPrivilegedOperations { /** * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(IBinder, boolean)}. * - * @param showInputToken dummy token that maps to window requesting - * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} + * @param showOrHideInputToken dummy token that maps to window requesting + * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} or + * {@link android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow + * (IBinder, int)} * @param setVisible {@code true} to set IME visible, else hidden. */ @AnyThread - public void applyImeVisibility(IBinder showInputToken, boolean setVisible) { + public void applyImeVisibility(IBinder showOrHideInputToken, boolean setVisible) { final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull(); if (ops == null) { return; } try { - ops.applyImeVisibility(showInputToken, setVisible); + ops.applyImeVisibility(showOrHideInputToken, setVisible); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java index 85643fcffa2f..c90d851201a2 100644 --- a/core/java/com/android/internal/logging/InstanceId.java +++ b/core/java/com/android/internal/logging/InstanceId.java @@ -48,6 +48,17 @@ public final class InstanceId implements Parcelable { return mId; } + /** + * Create a fake instance ID for testing purposes. Not for production use. See also + * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence. + * @param id The ID you want to assign. + * @return new InstanceId. + */ + @VisibleForTesting + public static InstanceId fakeInstanceId(int id) { + return new InstanceId(id); + } + @Override public int hashCode() { return mId; diff --git a/core/java/com/android/internal/logging/InstanceIdSequence.java b/core/java/com/android/internal/logging/InstanceIdSequence.java index aa507e538944..34643105b965 100644 --- a/core/java/com/android/internal/logging/InstanceIdSequence.java +++ b/core/java/com/android/internal/logging/InstanceIdSequence.java @@ -25,7 +25,7 @@ import java.security.SecureRandom; import java.util.Random; /** - * Generates random InstanceIds in range [0, instanceIdMax) for passing to + * Generates random InstanceIds in range [1, instanceIdMax] for passing to * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on * first use; try to give it a long lifetime. Safe for concurrent use. */ @@ -34,12 +34,12 @@ public class InstanceIdSequence { private final Random mRandom = new SecureRandom(); /** - * Constructs a sequence with identifiers [0, instanceIdMax). Capped at INSTANCE_ID_MAX. + * Constructs a sequence with identifiers [1, instanceIdMax]. Capped at INSTANCE_ID_MAX. * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get - * an all-zero sequence. + * an all-1 sequence. */ public InstanceIdSequence(int instanceIdMax) { - mInstanceIdMax = min(max(0, instanceIdMax), InstanceId.INSTANCE_ID_MAX); + mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX); } /** @@ -47,7 +47,7 @@ public class InstanceIdSequence { * @return new InstanceId */ public InstanceId newInstanceId() { - return newInstanceIdInternal(mRandom.nextInt(mInstanceIdMax)); + return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax)); } /** diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 75eb4aa052b0..140c410e8de6 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -55,11 +55,8 @@ public class MetricsLogger { protected void saveLog(LogMaker log) { // TODO(b/116684537): Flag guard logging to event log and statsd socket. EventLogTags.writeSysuiMultiAction(log.serialize()); - if (log.getCategory() != MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER - && log.getCategory() != MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM) { - FrameworkStatsLog.write(FrameworkStatsLog.KEY_VALUE_PAIRS_ATOM, - /* UID is retrieved from statsd side */ 0, log.getEntries()); - } + FrameworkStatsLog.write(FrameworkStatsLog.KEY_VALUE_PAIRS_ATOM, + /* UID is retrieved from statsd side */ 0, log.getEntries()); } public static final int VIEW_UNKNOWN = MetricsEvent.VIEW_UNKNOWN; diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index a47bd17f45af..54cf693490e9 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -19,6 +19,9 @@ package com.android.internal.os; import static android.system.OsConstants.S_IRWXG; import static android.system.OsConstants.S_IRWXO; +import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START; +import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START; + import android.app.ApplicationLoaders; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.SharedLibraryInfo; @@ -52,7 +55,7 @@ import android.util.TimingsTraceLog; import android.webkit.WebViewFactory; import android.widget.TextView; -import com.android.internal.logging.MetricsLogger; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; import dalvik.system.DexFile; @@ -863,11 +866,10 @@ public class ZygoteInit { Runnable caller; try { - // Report Zygote start time to tron unless it is a runtime restart - if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { - MetricsLogger.histogram(null, "boot_zygote_init", - (int) SystemClock.elapsedRealtime()); - } + // Store now for StatsLogging later. + final long startTime = SystemClock.elapsedRealtime(); + final boolean isRuntimeRestarted = "1".equals( + SystemProperties.get("sys.boot_completed")); String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag, @@ -894,6 +896,17 @@ public class ZygoteInit { } final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); + if (!isRuntimeRestarted) { + if (isPrimaryZygote) { + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, + BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START, + startTime); + } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) { + FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, + BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START, + startTime); + } + } if (abiList == null) { throw new RuntimeException("No ABI list supplied."); diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 24222d3afb72..138d0dd39537 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -135,6 +135,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final static String TAG = "PhoneWindow"; + /** + * @see Window#setDecorFitsSystemWindows + */ + private static final OnContentApplyWindowInsetsListener sDefaultContentInsetsApplier = + (view, insets) -> { + if ((view.getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) { + return new Pair<>(Insets.NONE, insets); + } + + boolean includeIme = (view.getViewRootImpl().mWindowAttributes.softInputMode + & SOFT_INPUT_MASK_ADJUST) + == SOFT_INPUT_ADJUST_RESIZE; + Insets insetsToApply; + if (ViewRootImpl.sNewInsetsMode == 0) { + insetsToApply = insets.getSystemWindowInsets(); + } else { + insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0)); + } + insets = insets.inset(insetsToApply); + return new Pair<>(insetsToApply, + insets.inset(insetsToApply).consumeSystemWindowInsets()); + }; + /* If true, shadows drawn around the window will be rendered by the system compositor. If * false, shadows will be drawn by the client by setting an elevation on the root view and * the contents will be inset by the shadow radius. */ @@ -320,8 +343,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /** @see ViewRootImpl#mActivityConfigCallback */ private ActivityConfigCallback mActivityConfigCallback; - private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener - = createDefaultContentWindowInsetsListener(); + private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener = + sDefaultContentInsetsApplier; static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( @@ -2120,27 +2143,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mPendingOnContentApplyWindowInsetsListener = null; } - private OnContentApplyWindowInsetsListener createDefaultContentWindowInsetsListener() { - return insets -> { - if ((getDecorView().getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) { - return new Pair<>(Insets.NONE, insets); - } - - boolean includeIme = - (getViewRootImpl().mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST) - == SOFT_INPUT_ADJUST_RESIZE; - Insets insetsToApply; - if (ViewRootImpl.sNewInsetsMode == 0) { - insetsToApply = insets.getSystemWindowInsets(); - } else { - insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0)); - } - insets = insets.inset(insetsToApply); - return new Pair<>(insetsToApply, - insets.inset(insetsToApply).consumeSystemWindowInsets()); - }; - } - static private final String FOCUSED_ID_TAG = "android:focusedViewId"; static private final String VIEWS_TAG = "android:views"; static private final String PANELS_TAG = "android:Panels"; @@ -3907,7 +3909,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) { ViewRootImpl impl = getViewRootImplOrNull(); OnContentApplyWindowInsetsListener listener = decorFitsSystemWindows - ? createDefaultContentWindowInsetsListener() + ? sDefaultContentInsetsApplier : null; if (impl != null) { impl.setOnContentApplyWindowInsetsListener(listener); diff --git a/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl index 0f93b8ebdb53..5a78e0d3082d 100644 --- a/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl +++ b/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl @@ -16,6 +16,7 @@ package com.android.internal.view; +import android.view.autofill.AutofillId; import android.view.inputmethod.InlineSuggestionsResponse; /** @@ -23,5 +24,5 @@ import android.view.inputmethod.InlineSuggestionsResponse; * {@hide} */ oneway interface IInlineSuggestionsResponseCallback { - void onInlineSuggestionsResponse(in InlineSuggestionsResponse response); + void onInlineSuggestionsResponse(in AutofillId fieldId, in InlineSuggestionsResponse response); } diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl index fd4b5abe2b21..40e4f4d6ad12 100644 --- a/core/java/com/android/internal/view/IInputMethod.aidl +++ b/core/java/com/android/internal/view/IInputMethod.aidl @@ -55,7 +55,7 @@ oneway interface IInputMethod { void showSoftInput(in IBinder showInputToken, int flags, in ResultReceiver resultReceiver); - void hideSoftInput(int flags, in ResultReceiver resultReceiver); + void hideSoftInput(in IBinder hideInputToken, int flags, in ResultReceiver resultReceiver); void changeInputMethodSubtype(in InputMethodSubtype subtype); } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 0337ddd1ab49..3f03f2a3e754 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -43,7 +43,7 @@ interface IInputMethodManager { boolean showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags, in ResultReceiver resultReceiver); - boolean hideSoftInput(in IInputMethodClient client, int flags, + boolean hideSoftInput(in IInputMethodClient client, IBinder windowToken, int flags, in ResultReceiver resultReceiver); // If windowToken is null, this just does startInput(). Otherwise this reports that a window // has gained focus, and if 'attribute' is non-null then also does startInput. diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl index 664643cc9b4d..0319e3637384 100644 --- a/core/java/com/android/internal/view/IInputMethodSession.aidl +++ b/core/java/com/android/internal/view/IInputMethodSession.aidl @@ -50,4 +50,6 @@ oneway interface IInputMethodSession { void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo); void notifyImeHidden(); + + void removeImeSurface(); } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index d27be275f312..ade2c7d86faf 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -208,7 +208,6 @@ cc_library_shared { "libseccomp_policy", "libgrallocusage", "libscrypt_static", - "libstatssocket", ], shared_libs: [ @@ -266,6 +265,7 @@ cc_library_shared { "libdl", "libdl_android", "libstatslog", + "libstatssocket", "libtimeinstate", "server_configurable_flags", "libstatspull", diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 84acf9ac6989..0a2b1d4a661f 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -114,9 +114,9 @@ status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* even uint32_t publishedSeq = mNextPublishedSeq++; status_t status = - mInputPublisher.publishKeyEvent(publishedSeq, event->getDeviceId(), event->getSource(), - event->getDisplayId(), event->getHmac(), - event->getAction(), event->getFlags(), + mInputPublisher.publishKeyEvent(publishedSeq, event->getId(), event->getDeviceId(), + event->getSource(), event->getDisplayId(), + event->getHmac(), event->getAction(), event->getFlags(), event->getKeyCode(), event->getScanCode(), event->getMetaState(), event->getRepeatCount(), event->getDownTime(), event->getEventTime()); @@ -138,12 +138,12 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent for (size_t i = 0; i <= event->getHistorySize(); i++) { publishedSeq = mNextPublishedSeq++; status_t status = - mInputPublisher.publishMotionEvent(publishedSeq, event->getDeviceId(), - event->getSource(), event->getDisplayId(), - event->getHmac(), event->getAction(), - event->getActionButton(), event->getFlags(), - event->getEdgeFlags(), event->getMetaState(), - event->getButtonState(), + mInputPublisher.publishMotionEvent(publishedSeq, event->getId(), + event->getDeviceId(), event->getSource(), + event->getDisplayId(), event->getHmac(), + event->getAction(), event->getActionButton(), + event->getFlags(), event->getEdgeFlags(), + event->getMetaState(), event->getButtonState(), event->getClassification(), event->getXScale(), event->getYScale(), event->getXOffset(), event->getYOffset(), event->getXPrecision(), diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp index bbe563e12a4c..54567e5010c5 100644 --- a/core/jni/android_view_KeyEvent.cpp +++ b/core/jni/android_view_KeyEvent.cpp @@ -75,6 +75,7 @@ static struct { jmethodID obtain; jmethodID recycle; + jfieldID mId; jfieldID mDeviceId; jfieldID mSource; jfieldID mDisplayId; @@ -96,6 +97,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) { ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac()); jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain, + event->getId(), nanoseconds_to_milliseconds(event->getDownTime()), nanoseconds_to_milliseconds(event->getEventTime()), event->getAction(), event->getKeyCode(), @@ -114,6 +116,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) { status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, KeyEvent* event) { + jint id = env->GetIntField(eventObj, gKeyEventClassInfo.mId); jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId); jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource); jint displayId = env->GetIntField(eventObj, gKeyEventClassInfo.mDisplayId); @@ -131,7 +134,7 @@ status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime); jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime); - event->initialize(deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode, + event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode, metaState, repeatCount, milliseconds_to_nanoseconds(downTime), milliseconds_to_nanoseconds(eventTime)); return OK; @@ -159,14 +162,18 @@ static jint android_view_KeyEvent_nativeKeyCodeFromString(JNIEnv* env, jobject c return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str()); } +static jint android_view_KeyEvent_nativeNextId() { + return static_cast<jint>(InputEvent::nextId()); +} // ---------------------------------------------------------------------------- static const JNINativeMethod g_methods[] = { - { "nativeKeyCodeToString", "(I)Ljava/lang/String;", - (void*)android_view_KeyEvent_nativeKeyCodeToString}, - { "nativeKeyCodeFromString", "(Ljava/lang/String;)I", - (void*)android_view_KeyEvent_nativeKeyCodeFromString}, + {"nativeKeyCodeToString", "(I)Ljava/lang/String;", + (void*)android_view_KeyEvent_nativeKeyCodeToString}, + {"nativeKeyCodeFromString", "(Ljava/lang/String;)I", + (void*)android_view_KeyEvent_nativeKeyCodeFromString}, + {"nativeNextId", "()I", (void*)android_view_KeyEvent_nativeNextId}, }; int register_android_view_KeyEvent(JNIEnv* env) { @@ -175,10 +182,11 @@ int register_android_view_KeyEvent(JNIEnv* env) { gKeyEventClassInfo.obtain = GetStaticMethodIDOrDie(env, gKeyEventClassInfo.clazz, "obtain", - "(JJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;"); + "(IJJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;"); gKeyEventClassInfo.recycle = GetMethodIDOrDie(env, gKeyEventClassInfo.clazz, "recycle", "()V"); + gKeyEventClassInfo.mId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mId", "I"); gKeyEventClassInfo.mDeviceId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDeviceId", "I"); gKeyEventClassInfo.mSource = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mSource", "I"); gKeyEventClassInfo.mDisplayId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDisplayId", diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 3335fb23cfb7..9816d713c6dc 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -369,9 +369,10 @@ static jlong android_view_MotionEvent_nativeInitialize( env->DeleteLocalRef(pointerCoordsObj); } - event->initialize(deviceId, source, displayId, INVALID_HMAC, action, 0, flags, edgeFlags, - metaState, buttonState, static_cast<MotionClassification>(classification), - 1 /*xScale*/, 1 /*yScale*/, xOffset, yOffset, xPrecision, yPrecision, + event->initialize(InputEvent::nextId(), deviceId, source, displayId, INVALID_HMAC, action, 0, + flags, edgeFlags, metaState, buttonState, + static_cast<MotionClassification>(classification), 1 /*xScale*/, 1 /*yScale*/, + xOffset, yOffset, xPrecision, yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords); @@ -592,6 +593,11 @@ static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sour return reinterpret_cast<jlong>(destEvent); } +static jint android_view_MotionEvent_nativeGetId(jlong nativePtr) { + MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); + return event->getId(); +} + static jint android_view_MotionEvent_nativeGetDeviceId(jlong nativePtr) { MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr); return event->getDeviceId(); @@ -790,6 +796,7 @@ static const JNINativeMethod gMotionEventMethods[] = { // --------------- @CriticalNative ------------------ {"nativeCopy", "(JJZ)J", (void*)android_view_MotionEvent_nativeCopy}, + {"nativeGetId", "(J)I", (void*)android_view_MotionEvent_nativeGetId}, {"nativeGetDeviceId", "(J)I", (void*)android_view_MotionEvent_nativeGetDeviceId}, {"nativeGetSource", "(J)I", (void*)android_view_MotionEvent_nativeGetSource}, {"nativeSetSource", "(JI)V", (void*)android_view_MotionEvent_nativeSetSource}, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index a9ef257359c2..b2ca0a7bcbe3 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -91,6 +91,7 @@ static struct { jfieldID refreshRate; jfieldID appVsyncOffsetNanos; jfieldID presentationDeadlineNanos; + jfieldID configGroup; } gDisplayConfigClassInfo; static struct { @@ -874,6 +875,7 @@ static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz, jobject t config.appVsyncOffset); env->SetLongField(object, gDisplayConfigClassInfo.presentationDeadlineNanos, config.presentationDeadline); + env->SetIntField(object, gDisplayConfigClassInfo.configGroup, config.configGroup); env->SetObjectArrayElement(configArray, static_cast<jsize>(c), object); env->DeleteLocalRef(object); } @@ -1614,6 +1616,7 @@ int register_android_view_SurfaceControl(JNIEnv* env) GetFieldIDOrDie(env, configClazz, "appVsyncOffsetNanos", "J"); gDisplayConfigClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env, configClazz, "presentationDeadlineNanos", "J"); + gDisplayConfigClassInfo.configGroup = GetFieldIDOrDie(env, configClazz, "configGroup", "I"); jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect"); gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I"); diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index e4141e02ab1c..4e139a34c555 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -626,12 +626,6 @@ static void PreApplicationInit() { // Set the jemalloc decay time to 1. mallopt(M_DECAY_TIME, 1); - - // Maybe initialize GWP-ASan here. Must be called after - // mallopt(M_SET_ZYGOTE_CHILD). - bool ForceEnableGwpAsan = false; - android_mallopt(M_INITIALIZE_GWP_ASAN, &ForceEnableGwpAsan, - sizeof(ForceEnableGwpAsan)); } static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) { @@ -799,31 +793,6 @@ static void MountAppDataTmpFs(const std::string& target_dir, } } -static void BindMountObbPackage(std::string_view package_name, int userId, fail_fn_t fail_fn) { - - // TODO(148772775): Pass primary volume name from zygote argument to here - std::string source; - if (IsFilesystemSupported("sdcardfs")) { - source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s", - userId, package_name.data()); - } else { - source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s", - userId, userId, package_name.data()); - } - std::string target( - StringPrintf("/storage/emulated/%d/Android/obb/%s", userId, package_name.data())); - - if (access(source.c_str(), F_OK) != 0) { - fail_fn(CREATE_ERROR("Cannot access source %s: %s", source.c_str(), strerror(errno))); - } - - if (access(target.c_str(), F_OK) != 0) { - fail_fn(CREATE_ERROR("Cannot access target %s: %s", target.c_str(), strerror(errno))); - } - - BindMount(source, target, fail_fn); -} - // Create a private mount namespace and bind mount appropriate emulated // storage for the given user. static void MountEmulatedStorage(uid_t uid, jint mount_mode, @@ -1546,10 +1515,39 @@ static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list, } } -// Bind mount all obb directories that are visible to this app. +static void BindMountStorageToLowerFs(const userid_t user_id, const char* dir_name, + const char* package, fail_fn_t fail_fn) { + + bool hasPackage = (package != nullptr); + bool hasSdcardFs = IsFilesystemSupported("sdcardfs"); + std::string source; + if (hasSdcardFs) { + source = hasPackage ? + StringPrintf("/mnt/runtime/default/emulated/%d/%s/%s", user_id, dir_name, package) : + StringPrintf("/mnt/runtime/default/emulated/%d/%s", user_id, dir_name); + } else { + source = hasPackage ? + StringPrintf("/mnt/pass_through/%d/emulated/%d/%s/%s", + user_id, user_id, dir_name, package) : + StringPrintf("/mnt/pass_through/%d/emulated/%d/%s", user_id, user_id, dir_name); + } + std::string target = hasPackage ? + StringPrintf("/storage/emulated/%d/%s/%s", user_id, dir_name, package) : + StringPrintf("/storage/emulated/%d/%s", user_id, dir_name); + + if (access(source.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno))); + } + if (access(target.c_str(), F_OK) != 0) { + fail_fn(CREATE_ERROR("Error accessing %s: %s", target.c_str(), strerror(errno))); + } + BindMount(source, target, fail_fn); +} + +// Bind mount all obb & data directories that are visible to this app. // If app data isolation is not enabled for this process, bind mount the whole obb -// directory instead. -static void BindMountAppObbDirs(JNIEnv* env, jobjectArray pkg_data_info_list, +// and data directory instead. +static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list, uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) { auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); @@ -1577,18 +1575,8 @@ static void BindMountAppObbDirs(JNIEnv* env, jobjectArray pkg_data_info_list, if (size == 0) { // App data isolation is not enabled for this process, so we bind mount to whole obb/ dir. - std::string source; - if (IsFilesystemSupported("sdcardfs")) { - source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", user_id); - } else { - source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", user_id, user_id); - } - std::string target(StringPrintf("/storage/emulated/%d/Android/obb", user_id)); - - if (access(source.c_str(), F_OK) != 0) { - fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno))); - } - BindMount(source, target, fail_fn); + BindMountStorageToLowerFs(user_id, "Android/obb", /* package */ nullptr, fail_fn); + BindMountStorageToLowerFs(user_id, "Android/data", /* package */ nullptr, fail_fn); return; } @@ -1596,7 +1584,8 @@ static void BindMountAppObbDirs(JNIEnv* env, jobjectArray pkg_data_info_list, for (int i = 0; i < size; i += 3) { jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i)); std::string packageName = extract_fn(package_str).value(); - BindMountObbPackage(packageName, user_id, fail_fn); + BindMountStorageToLowerFs(user_id, "Android/obb", packageName.c_str(), fail_fn); + BindMountStorageToLowerFs(user_id, "Android/data", packageName.c_str(), fail_fn); } } @@ -1651,7 +1640,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && GetBoolProperty(kPropFuse, false) && GetBoolProperty(ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) { - BindMountAppObbDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); + BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); } // If this zygote isn't root, it won't be able to create a process group, diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto index d2bf20591f92..41863bbbfbf1 100644 --- a/core/proto/android/app/job/enums.proto +++ b/core/proto/android/app/job/enums.proto @@ -34,5 +34,5 @@ enum StopReasonEnum { STOP_REASON_TIMEOUT = 3; STOP_REASON_DEVICE_IDLE = 4; STOP_REASON_DEVICE_THERMAL = 5; - STOP_REASON_RESTRAINED = 6; + STOP_REASON_RESTRICTED_BUCKET = 6; } diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 4bef2e38ad55..bd1bae6d83fb 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -670,7 +670,7 @@ message StateControllerProto { repeated ExecutionStats execution_stats = 4; - optional AlarmListener in_quota_alarm_listener = 5; + reserved 5; // in_quota_alarm_listener } repeated PackageStats package_stats = 5; @@ -683,7 +683,25 @@ message StateControllerProto { } repeated UidPackageMapping uid_to_package_cache = 7; - // Next tag: 8 + message InQuotaAlarmListener { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + // The time at which the alarm is set to go off, in the elapsed realtime timebase. + optional int64 trigger_time_elapsed = 1; + + message Alarm { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional Package pkg = 1; + + // The time at which the package will be in quota, in the elapsed realtime timebase. + optional int64 in_quota_time_elapsed = 2; + } + repeated Alarm alarms = 2; + } + optional InQuotaAlarmListener in_quota_alarm_listener = 8; + + // Next tag: 9 } message StorageController { option (.android.msg_privacy).dest = DEST_AUTOMATIC; diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto index 6850d0109913..0455d58f498b 100644 --- a/core/proto/android/server/powermanagerservice.proto +++ b/core/proto/android/server/powermanagerservice.proto @@ -225,9 +225,10 @@ message PowerServiceSettingsAndConfigurationDumpProto { message ScreenBrightnessSettingLimitsProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional int32 setting_minimum = 1; - optional int32 setting_maximum = 2; - optional int32 setting_default = 3; + reserved 1, 2, 3; // setting_minimum, setting_maximum, setting_default + optional float setting_minimum_float = 4; + optional float setting_maximum_float = 5; + optional float setting_default_float = 6; } // True to decouple auto-suspend mode from the display state. diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 08db4544d5e7..e8a0b46e8430 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -167,7 +167,7 @@ message DisplayContentProto { optional WindowContainerProto window_container = 1; optional int32 id = 2; reserved 3; // stacks - optional DockedStackDividerControllerProto docked_stack_divider_controller = 4; + optional DockedStackDividerControllerProto docked_stack_divider_controller = 4 [deprecated=true]; // Will be removed soon. optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true]; /* non app windows */ @@ -229,7 +229,7 @@ message DisplayFramesProto { message DockedStackDividerControllerProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional bool minimized_dock = 1; + optional bool minimized_dock = 1 [deprecated=true]; } /* represents PinnedStackController */ diff --git a/core/proto/android/service/appwidget.proto b/core/proto/android/service/appwidget.proto index cd7173a94a70..97350ef90eec 100644 --- a/core/proto/android/service/appwidget.proto +++ b/core/proto/android/service/appwidget.proto @@ -36,4 +36,5 @@ message WidgetProto { optional int32 minHeight = 7; optional int32 maxWidth = 8; optional int32 maxHeight = 9; + optional bool restoreCompleted = 10; } diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml index 9aecfd99098f..fdd965f3b157 100644 --- a/core/res/res/layout/resolve_grid_item.xml +++ b/core/res/res/layout/resolve_grid_item.xml @@ -18,7 +18,7 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" - android:layout_width="@dimen/chooser_target_width" + android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="100dp" android:gravity="center" diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 2e939044459f..af56edd2353b 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Jou organisasie bestuur hierdie toestel en kan netwerkverkeer monitor. Tik vir besonderhede."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Ligginginstellings is deur jou administrateur verander"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tik om jou ligginginstellings te sien."</string> + <string name="country_detector" msgid="7023275114706088854">"Landaanwyser"</string> + <string name="location_service" msgid="2439187616018455546">"Liggingdiens"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensorkennisgewingdiens"</string> + <string name="twilight_service" msgid="8964898045693187224">"Skemerdiens"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die administrasieprogram kan nie gebruik word nie. Jou toestel sal nou uitgevee word.\n\nKontak jou organisasie se administrateur as jy vrae het."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Druk is gedeaktiveer deur <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Neem skermkiekie vir foutverslag oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes.</item> <item quantity="one">Neem skermkiekie vir foutverslag oor <xliff:g id="NUMBER_0">%d</xliff:g> sekonde.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Stilmodus"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Klank is AF"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Klank is AAN"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probeer weer."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukke is geregistreer nie."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor is tydelik gedeaktiveer."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Kan nie gesig verifieer nie. Probeer weer."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Jy het nie gesigslot opgestel nie."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gesigslot word nie op hierdie toestel gesteun nie."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor is tydelik gedeaktiveer."</string> <string name="face_name_template" msgid="3877037340223318119">"Gesig <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-ontfouting gekoppel"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tik om USB-ontfouting af te skakel"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Kies om USB-ontfouting te deaktiveer."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Draadlose ontfouting is gekoppel"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tik om draadlose ontfouting af te skakel"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Kies om draadlose ontfouting te deaktiveer."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Toetsraamwerkmodus is geaktiveer"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Voer \'n fabriekterugstelling uit om Toetsraamwerkmodus te deaktiveer."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Reekskonsole is geaktiveer"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Die voorgronddiens wat in die agtergrond begin het vanaf <xliff:g id="PACKAGENAME">%1$s</xliff:g> sal nie ingebruik-toestemming hê in toekomstige R-bouweergawes nie. Raadpleeg asseblief go/r-bg-fgs-restriction en dien \'n foutverslag in."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gebruik toeganklikheidkortpad?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Wysig kortpaaie"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Kanselleer"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Skakel kortpad af"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Ongekategoriseer"</string> <string name="importance_from_user" msgid="2782756722448800447">"Jy stel die belangrikheid van hierdie kennisgewings."</string> <string name="importance_from_person" msgid="4235804979664465383">"Dit is belangrik as gevolg van die mense wat betrokke is."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string> <string name="language_selection_title" msgid="52674936078683285">"Voeg \'n taal by"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlik"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Kan nie met werkprogramme deel nie"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kan nie met persoonlike programme deel nie"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Jou IT-admin het deling tussen persoonlike en werkprogramme geblokkeer"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Skakel werkprogramme aan"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Skakel werkprogramme aan om toegang tot werkprogramme en -kontakte te kry"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Geen programme beskikbaar nie"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Ons kon geen programme kry nie"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Skakel werk aan"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Neem oudio in telefonie-oproepe op of speel dit"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Laat hierdie program, indien dit as die verstekbellerprogram aangewys is, toe om oudio in telefonie-oproepe op te neem of te speel."</string> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index f49e2ef11ade..9a0ed24f2ede 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"የእርስዎ ድርጅት ይህን መሣሪያ ያስተዳድራል፣ እና የአውታረ መረብ ትራፊክን ሊከታተል ይችላል። ዝርዝሮችን ለማግኘት መታ ያድርጉ።"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"የአካባቢ ቅንብሮች በአስተዳዳሪዎ ተቀይረዋል"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"የአካባቢ ቅንብሮችዎን ለመመልከት መታ ያድርጉ።"</string> + <string name="country_detector" msgid="7023275114706088854">"የአገር ማወቂያ"</string> + <string name="location_service" msgid="2439187616018455546">"የአካባቢ አገልግሎት"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"የዳሳሽ ማሳወቂያ አገልግሎት"</string> + <string name="twilight_service" msgid="8964898045693187224">"የውጋገን አገልግሎት"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string> <string name="factory_reset_message" msgid="2657049595153992213">"የአስተዳዳሪ መተግበሪያ ስራ ላይ ሊውል አይችልም። የእርስዎን መሣሪያ አሁን ይደመሰሳል።\n\nጥያቄዎች ካለዎት የድርጅትዎን አስተዳዳሪ ያነጋግሩ።"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ማተም በ<xliff:g id="OWNER_APP">%s</xliff:g> ተሰናክሏል።"</string> @@ -245,6 +249,10 @@ <item quantity="one">በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች ውስጥ ለሳንካ ሪፖርት ቅጽበታዊ ገጽ ዕይታን በማንሳት ላይ።</item> <item quantity="other">በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች ውስጥ ለሳንካ ሪፖርት ቅጽበታዊ ገጽ ዕይታን በማንሳት ላይ።</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"የፀጥታ ሁነታ"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ድምፅ ጠፍቷል"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ድምፅ በርቷል"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"እንደገና ይሞክሩ።"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ምንም የጣት አሻራዎች አልተመዘገቡም።"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ጣት <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"ፊትን ማረጋገጥ አይቻልም። እንደገና ይሞክሩ።"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"በመልክ መክፈትን አላቀናበሩም።"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"በመልክ መክፈት መስጫ በዚህ መሣሪያ ላይ አይደገፍም።"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string> <string name="face_name_template" msgid="3877037340223318119">"ፊት <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB አድስ ተያይዟል"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"የዩኤስቢ ማረሚያን ለማጥፋት መታ ያድርጉ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ማረሚያ ላለማንቃት ምረጥ።"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ገመድ-አልባ ማረም ተገናኝቷል"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ገመድ-አልባ ማረምን ለማጥፋት ይምረጡ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ገመድ-አልባ ማረምን ለማሰናከል ይምረጡ።"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"የሙከራ ጥቅል ሁነታ ነቅቷል"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"የመሞከሪያ ጥቅል ሁነታን ለማሰናከል የፋብሪካ ዳግም ቅንብርን ይሞክሩ።"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ተከታታይ ኮንሶል ነቅቷል"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ዳራው ከ<xliff:g id="PACKAGENAME">%1$s</xliff:g> የጀመረው የፊት አገልግሎት ወደፊት በሚኖሩት R ግንቦች ላይ ጥቅም ላይ እየዋለ ፈቃድ አይኖረውም። እባክዎ go/r-bg-fgs-restriction እና ፋይል ሳንካ ሪፖርትን ይመልከቱ።"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ድምጹ ከሚመከረው መጠን በላይ ከፍ ይበል?\n\nበከፍተኛ ድምጽ ለረጅም ጊዜ ማዳመጥ ጆሮዎን ሊጎዳው ይችላል።"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"የተደራሽነት አቋራጭ ጥቅም ላይ ይዋል?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"አቋራጩ ሲበራ ሁለቱንም የድምጽ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"አቋራጮችን አርትዕ ያድርጉ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ይቅር"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"አቋራጩን አጥፋ"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"ያልተመደቡ"</string> <string name="importance_from_user" msgid="2782756722448800447">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string> <string name="importance_from_person" msgid="4235804979664465383">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት (ይህ መለያ ያለው ተጠቃሚ አስቀድሞ አለ)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> አዲስ ተጠቃሚ ከ <xliff:g id="ACCOUNT">%2$s</xliff:g> ጋር መፍጠር እንዲችል ይፍቀዱ?"</string> <string name="language_selection_title" msgid="52674936078683285">"ቋንቋ ያክሉ"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"የግል"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ሥራ"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"በሥራ መተግበሪያዎች ማጋራት አይቻልም"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"በግል መተግበሪያዎች ማጋራት አይቻልም"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"የእርስዎ አይቲ አስተዳዳሪ በግል እና በሥራ መተግበሪያዎች መካከል ማጋራትን አግደዋል"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"የሥራ መተግበሪያዎች ያብሩ"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"የሥራ መተግበሪያዎች እና እውቂያዎችን ለመድረስ የሥራ መተግበሪያዎችን ያብሩ"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ምንም መተግበሪያዎች አይገኙም"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ምንም መተግበሪያዎች ልናገኝ አልቻልንም"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"ሥራን ያብሩ"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"በስልክ ጥሪዎች ላይ ኦዲዮን መቅዳት ወይም ማጫወት"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ይህ መተግበሪያ እንደ ነባሪ የመደወያ መተግበሪያ ሲመደብ በስልክ ጥሪዎች ላይ ኦዲዮን እንዲቀዳ ወይም እንዲያጫውት ያስችለዋል።"</string> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 93f5dc187ade..7d1e01d5d235 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -123,12 +123,12 @@ <string name="roamingText8" msgid="7774800704373721973">"التجوال - شريك متميز"</string> <string name="roamingText9" msgid="1933460020190244004">"تجوال - وظائف الخدمة الكاملة"</string> <string name="roamingText10" msgid="7434767033595769499">"تجوال - وظائف الخدمة الجزئية"</string> - <string name="roamingText11" msgid="5245687407203281407">"إعلان بانر للتجوال قيد التشغيل"</string> + <string name="roamingText11" msgid="5245687407203281407">"إعلان بانر للتجوال قيد التفعيل"</string> <string name="roamingText12" msgid="673537506362152640">"إعلان بانر للتجوال متوقف"</string> <string name="roamingTextSearching" msgid="5323235489657753486">"البحث عن خدمة"</string> <string name="wfcRegErrorTitle" msgid="3193072971584858020">"تعذّر إعداد الاتصال عبر Wi‑Fi."</string> <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="468830943567116703">"لإجراء مكالمات وإرسال رسائل عبر Wi-Fi، اطلب من مشغّل شبكة الجوّال أولاً إعداد هذه الخدمة، ثم شغّل الاتصال عبر Wi-Fi مرة أخرى من خلال الإعدادات. (رمز الخطأ: <xliff:g id="CODE">%1$s</xliff:g>)"</item> + <item msgid="468830943567116703">"لإجراء مكالمات وإرسال رسائل عبر Wi-Fi، اطلب من مفعِّل شبكة الجوّال أولاً إعداد هذه الخدمة، ثم فعِّل الاتصال عبر Wi-Fi مرة أخرى من خلال الإعدادات. (رمز الخطأ: <xliff:g id="CODE">%1$s</xliff:g>)"</item> </string-array> <string-array name="wfcOperatorErrorNotificationMessages"> <item msgid="4795145070505729156">"حدثت مشكلة أثناء تسجيل الاتصال عبر Wi‑Fi باستخدام مشغِّل شبكة الجوّال: <xliff:g id="CODE">%1$s</xliff:g>"</item> @@ -199,10 +199,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"تنازل المشرف عن الجهاز للاستخدام الشخصي"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"تتم إدارة الجهاز"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"تدير مؤسستك هذا الجهاز ويمكنها مراقبة حركة بيانات الشبكة. يمكنك النقر للحصول على تفاصيل."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"غيّرَ مشرفك إعدادات الموقع الجغرافي"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"انقر لعرض إعدادات الموقع الجغرافي."</string> + <string name="country_detector" msgid="7023275114706088854">"أداة التعرّف على البلدان"</string> + <string name="location_service" msgid="2439187616018455546">"خدمات الموقع الجغرافي"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"خدمة إشعارات جهاز الاستشعار"</string> + <string name="twilight_service" msgid="8964898045693187224">"خدمة الغسق"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string> <string name="factory_reset_message" msgid="2657049595153992213">"تعذّر استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nإذا كانت لديك أسئلة، اتصل بمشرف مؤسستك."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -220,7 +222,7 @@ <string name="silent_mode_silent" msgid="5079789070221150912">"إيقاف الرنين"</string> <string name="silent_mode_vibrate" msgid="8821830448369552678">"اهتزاز الرنين"</string> <string name="silent_mode_ring" msgid="6039011004781526678">"تشغيل الرنين"</string> - <string name="reboot_to_update_title" msgid="2125818841916373708">"إعادة تحميل نظام Android"</string> + <string name="reboot_to_update_title" msgid="2125818841916373708">"تحديث نظام Android"</string> <string name="reboot_to_update_prepare" msgid="6978842143587422365">"جارٍ الإعداد للتحديث…"</string> <string name="reboot_to_update_package" msgid="4644104795527534811">"جارٍ معالجة حزمة التحديث…"</string> <string name="reboot_to_update_reboot" msgid="4474726009984452312">"جارٍ إعادة التشغيل…"</string> @@ -259,11 +261,15 @@ <item quantity="other">سيتم التقاط لقطة شاشة لتقرير الخطأ خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية.</item> <item quantity="one">سيتم التقاط لقطة شاشة لتقرير الخطأ خلال <xliff:g id="NUMBER_0">%d</xliff:g> ثانية.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"وضع صامت"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"الصوت متوقف"</string> - <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"الصوت قيد التشغيل"</string> + <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"الصوت قيد التفعيل"</string> <string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"وضع الطائرة"</string> - <string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"وضع الطائرة قيد التشغيل"</string> + <string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"وضع الطائرة قيد التفعيل"</string> <string name="global_actions_airplane_mode_off_status" msgid="8522219771500505475">"وضع الطائرة متوقف"</string> <string name="global_action_settings" msgid="4671878836947494217">"الإعدادات"</string> <string name="global_action_assist" msgid="2517047220311505805">"مساعدة"</string> @@ -321,7 +327,7 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"الوصول إلى بيانات المستشعر حول علاماتك الحيوية"</string> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"استرداد محتوى النافذة"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"فحص محتوى نافذة يتم التفاعل معها"</string> - <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"تشغيل الاستكشاف باللمس"</string> + <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"تفعيل الاستكشاف باللمس"</string> <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"سيتم قول العناصر التي تم النقر عليها بصوت عال ويمكن استكشاف الشاشة باستخدام الإيماءات."</string> <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"ملاحظة النص الذي تكتبه"</string> <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"يتضمن بيانات شخصية مثل أرقام بطاقات الائتمان وكلمات المرور."</string> @@ -372,7 +378,7 @@ <string name="permlab_reorderTasks" msgid="7598562301992923804">"إعادة ترتيب التطبيقات قيد التشغيل"</string> <string name="permdesc_reorderTasks" msgid="8796089937352344183">"للسماح للتطبيق بنقل المهام إلى المقدمة والخلفية. وقد يجري التطبيق ذلك بدون إذنك."</string> <string name="permlab_enableCarMode" msgid="893019409519325311">"تفعيل وضع السيارة"</string> - <string name="permdesc_enableCarMode" msgid="56419168820473508">"للسماح للتطبيق بتمكين وضع السيارة."</string> + <string name="permdesc_enableCarMode" msgid="56419168820473508">"للسماح للتطبيق بتفعيل وضع السيارة."</string> <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"إغلاق التطبيقات الأخرى"</string> <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"للسماح للتطبيق بإنهاء عمليات التطبيقات الأخرى في الخلفية. وقد يؤدي هذا إلى توقف تطبيقات أخرى عن العمل."</string> <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"يمكن لهذا التطبيق الظهور في مقدمة التطبيقات الأخرى"</string> @@ -424,7 +430,7 @@ <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"يستطيع هذا التطبيق إضافة أحداث تقويم إلى جهاز Android TV أو إزالتها أو تغييرها، ويمكنه أيضًا إرسال رسائل تبدو واردة من مالكي التقويم، أو تغيير الأحداث بدون إبلاغ مالكيها."</string> <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"يمكن لهذا التطبيق إضافة أحداث تقويم أو إزالتها أو تغييرها على الهاتف. كما يمكنه إرسال رسائل يبدو أنها واردة من مالكي التقويم، ويمكنه كذلك تغيير الأحداث بدون إشعار مالكيها."</string> <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"الدخول إلى المزيد من أوامر موفر الموقع"</string> - <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"للسماح للتطبيق بالدخول إلى أوامر إضافية لموفر الموقع. قد يتيح هذا للتطبيق التداخل مع تشغيل تقنية نظام تحديد المواقع العالمي (GPS) أو مصادر الموقع الأخرى."</string> + <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"للسماح للتطبيق بالدخول إلى أوامر إضافية لموفر الموقع. قد يتيح هذا للتطبيق التداخل مع تفعيل تقنية نظام تحديد المواقع العالمي (GPS) أو مصادر الموقع الأخرى."</string> <string name="permlab_accessFineLocation" msgid="6426318438195622966">"الوصول إلى الموقع الجغرافي الدقيق في الواجهة الأمامية فقط"</string> <string name="permdesc_accessFineLocation" msgid="9221079523494157324">"لا يمكن لهذا التطبيق معرفة موقعك الجغرافي بالضبط عندما يعمل في الخلفية. ويجب تفعيل خدمات الموقع الجغرافي وأن تكون متاحة على جهازك حتى يتمكن التطبيق من استخدامها. وقد يؤدي هذا إلى زيادة استهلاك طاقة البطارية."</string> <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"الوصول إلى الموقع الجغرافي التقريبي في الواجهة الأمامية فقط"</string> @@ -445,8 +451,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"إذا حصل تطبيق النظام على هذا الإذن، سيمكن لهذا التطبيق التقاط صور وتسجيل فيديوهات باستخدام كاميرا النظام في أي وقت. ويجب أن يحصل التطبيق أيضًا على الإذن android.permission.CAMERA."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"التحكم في الاهتزاز"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"للسماح للتطبيق بالتحكم في الهزّاز."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"يسمح هذا الإذن للتطبيق بالوصول إلى حالة الهزّاز."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"اتصال مباشر بأرقام الهواتف"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"للسماح للتطبيق بطلب أرقام هاتفية بدون تدخل منك. وقد يؤدي ذلك إلى تحمل رسوم غير متوقعة أو إجراء مكالمات غير متوقعة. ومن الجدير بالذكر أن ذلك لا يتيح للتطبيق الاتصال بأرقام الطوارئ. وقد تؤدي التطبيقات الضارة إلى تحملك تكاليف مالية من خلال إجراء مكالمات بدون موافقة منك."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"الوصول إلى خدمة الاتصال عبر الرسائل الفورية"</string> @@ -561,8 +566,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"أعد المحاولة."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ليست هناك بصمات إصبع مسجَّلة."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"تم إيقاف جهاز الاستشعار مؤقتًا."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"الإصبع <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -606,8 +610,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"يتعذّر التحقق من الوجه. حاول مرة أخرى."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"لم يسبق لك إعداد \"فتح القفل بالوجه\"."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"\"فتح القفل بالوجه\" غير متوفر على هذا الجهاز."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"تم إيقاف جهاز الاستشعار مؤقتًا."</string> <string name="face_name_template" msgid="3877037340223318119">"الوجه <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -695,8 +698,8 @@ <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"لضبط الخادم الوكيل العام في الجهاز على الاستخدام أثناء تفعيل السياسة. ولن يمكن لأحد سوى مالك الجهاز ضبط الخادم الوكيل العام."</string> <string name="policylab_expirePassword" msgid="6015404400532459169">"تعيين مدة انتهاء صلاحية كلمة مرور قفل الشاشة"</string> <string name="policydesc_expirePassword" msgid="9136524319325960675">"لتغيير عدد مرات تغيير كلمة المرور ورقم التعريف الشخصي والنمط في قفل الشاشة."</string> - <string name="policylab_encryptedStorage" msgid="9012936958126670110">"تعيين تشفير التخزين"</string> - <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"يمكنك طلب تشفير بيانات التطبيق المخزنة."</string> + <string name="policylab_encryptedStorage" msgid="9012936958126670110">"تعيين ترميز التخزين"</string> + <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"يمكنك طلب ترميز بيانات التطبيق المخزنة."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"إيقاف الكاميرات"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"يمكنك منع استخدام جميع كاميرات الجهاز."</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"إيقاف بعض ميزات قفل الشاشة"</string> @@ -864,12 +867,12 @@ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات تسجيل الدخول إلى Google.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء<xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة أخرى غير ناجحة، ستُطالب بإلغاء قفل جهاز Android TV باستخدام معلومات تسجيل الدخول إلى Google.\n\n يُرجى إعادة المحاولة بعد <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام معلومات تسجيل الدخول إلى Google.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> - <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"لقد حاولت فتح قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة، ستتم إعادة تعيين الجهاز اللوحي إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> + <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"لقد حاولت فتح قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%1$d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة، ستتم إعادة ضبط الجهاز اللوحي إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"لقد حاولت فتح قفل جهاز Android TV بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة أخرى غير ناجحة، ستتم إعادة ضبط جهاز Android TV على الإعداد التلقائي للمصنع وسيتم فقدان جميع بيانات المستخدمين."</string> - <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"لقد حاولت فتح قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة، ستتم إعادة تعيين الهاتف إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> - <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"لقد حاولت فتح قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> من المرات بشكل غير صحيح. سيتم الآن إعادة تعيين الجهاز اللوحي إلى الإعدادات الأساسية."</string> + <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"لقد حاولت فتح قفل الهاتف <xliff:g id="NUMBER_0">%1$d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة، ستتم إعادة ضبط الهاتف إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> + <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"لقد حاولت فتح قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> من المرات بشكل غير صحيح. سيتم الآن إعادة ضبط الجهاز اللوحي إلى الإعدادات الأساسية."</string> <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"لقد حاولت فتح قفل جهاز Android TV بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم الآن إعادة ضبط جهاز Android TV على الإعداد التلقائي للمصنع."</string> - <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"لقد حاولت فتح قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> من المرات بشكل غير صحيح. سيتم الآن إعادة تعيين الهاتف إلى الإعدادات الأساسية."</string> + <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"لقد حاولت فتح قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> من المرات بشكل غير صحيح. سيتم الآن إعادة ضبط الهاتف إلى الإعدادات الأساسية."</string> <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"حاول مرة أخرى خلال <xliff:g id="NUMBER">%d</xliff:g> ثانية."</string> <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"هل نسيت النمط؟"</string> <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"فتح قفل الحساب"</string> @@ -1260,7 +1263,7 @@ <string name="anr_activity_process" msgid="3477362583767128667">"<xliff:g id="ACTIVITY">%1$s</xliff:g> لا يستجيب"</string> <string name="anr_application_process" msgid="4978772139461676184">"<xliff:g id="APPLICATION">%1$s</xliff:g> لا يستجيب"</string> <string name="anr_process" msgid="1664277165911816067">"العملية <xliff:g id="PROCESS">%1$s</xliff:g> لا تستجيب"</string> - <string name="force_close" msgid="9035203496368973803">"موافق"</string> + <string name="force_close" msgid="9035203496368973803">"حسنًا"</string> <string name="report" msgid="2149194372340349521">"إرسال تقرير"</string> <string name="wait" msgid="7765985809494033348">"انتظار"</string> <string name="webpage_unresponsive" msgid="7850879412195273433">"أصبحت الصفحة لا تستجيب.\n\nهل تريد إغلاقها؟"</string> @@ -1274,18 +1277,18 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"العرض دائمًا"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"تم تصميم <xliff:g id="APP_NAME">%1$s</xliff:g> لإصدار غير متوافق من نظام تشغيل Android وقد يحدث خلل في أدائه. قد يتوفّر إصدار محدّث من التطبيق."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"الإظهار دائمًا"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"البحث عن إعادة تحميل"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"البحث عن تحديث"</string> <string name="smv_application" msgid="3775183542777792638">"انتهك التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) سياسة StrictMode المفروضة ذاتيًا."</string> <string name="smv_process" msgid="1398801497130695446">"انتهكت العملية <xliff:g id="PROCESS">%1$s</xliff:g> سياسة StrictMode المفروضة ذاتيًا."</string> - <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"جارٍ إعادة تحميل الهاتف…"</string> - <string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"جارٍ إعادة تحميل الجهاز اللوحي…"</string> - <string name="android_upgrading_title" product="device" msgid="6774767702998149762">"جارٍ إعادة تحميل الجهاز…"</string> + <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"جارٍ تحديث الهاتف…"</string> + <string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"جارٍ تحديث الجهاز اللوحي…"</string> + <string name="android_upgrading_title" product="device" msgid="6774767702998149762">"جارٍ تحديث الجهاز…"</string> <string name="android_start_title" product="default" msgid="4036708252778757652">"جارٍ بدء تشغيل الهاتف…"</string> <string name="android_start_title" product="automotive" msgid="7917984412828168079">"جارٍ تشغيل Android…"</string> <string name="android_start_title" product="tablet" msgid="4429767260263190344">"جارٍ بدء تشغيل الجهاز اللوحي…"</string> <string name="android_start_title" product="device" msgid="6967413819673299309">"جارٍ بدء تشغيل الجهاز…"</string> <string name="android_upgrading_fstrim" msgid="3259087575528515329">"جارٍ تحسين مساحة التخزين."</string> - <string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"جارٍ إنهاء إعادة تحميل النظام…"</string> + <string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"جارٍ إنهاء تحديث النظام…"</string> <string name="app_upgrading_toast" msgid="1016267296049455585">"جارٍ ترقية <xliff:g id="APPLICATION">%1$s</xliff:g>…"</string> <string name="android_upgrading_apk" msgid="1339564803894466737">"جارٍ تحسين التطبيق <xliff:g id="NUMBER_0">%1$d</xliff:g> من <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> <string name="android_preparing_apk" msgid="589736917792300956">"جارٍ تحضير <xliff:g id="APPNAME">%1$s</xliff:g>."</string> @@ -1401,6 +1404,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"تم توصيل تصحيح أخطاء الجهاز عبر USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"انقر لإيقاف تصحيح أخطاء الجهاز عبر USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"اختيار إيقاف تصحيح أخطاء USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"تم تفعيل ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\""</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"انقر لإيقاف ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\"."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"اختيار إيقاف ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\""</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"تم تفعيل وضع \"مفعّل الاختبار\""</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"يمكنك إجراء إعادة ضبط على الإعدادات الأصلية لإيقاف وضع \"مفعِّل اختبار\"."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"وحدة التحكّم التسلسلية مفعّلة"</string> @@ -1511,8 +1517,8 @@ <string name="vpn_title_long" msgid="6834144390504619998">"تم تفعيل VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string> <string name="vpn_text" msgid="2275388920267251078">"انقر لإدارة الشبكة."</string> <string name="vpn_text_long" msgid="278540576806169831">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. انقر لإدارة الشبكة."</string> - <string name="vpn_lockdown_connecting" msgid="6096725311950342607">"جارٍ الاتصال بشبكة افتراضية خاصة (VPN) دائمة التشغيل..."</string> - <string name="vpn_lockdown_connected" msgid="2853127976590658469">"تم الاتصال بشبكة افتراضية خاصة (VPN) دائمة التشغيل"</string> + <string name="vpn_lockdown_connecting" msgid="6096725311950342607">"جارٍ الاتصال بشبكة افتراضية خاصة (VPN) دائمة التفعيل..."</string> + <string name="vpn_lockdown_connected" msgid="2853127976590658469">"تم الاتصال بشبكة افتراضية خاصة (VPN) دائمة التفعيل"</string> <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"تم قطع الاتصال بالشبكة الافتراضية الخاصة (VPN) التي يتم تشغيلها دائمًا"</string> <string name="vpn_lockdown_error" msgid="4453048646854247947">"تعذّر الاتصال بشبكة VPN التي يتم تشغيلها دائمًا."</string> <string name="vpn_lockdown_config" msgid="8331697329868252169">"تغيير إعدادات الشبكة أو الشبكة الافتراضية الخاصة (VPN)"</string> @@ -1698,12 +1704,12 @@ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"لقد كتبت رمز PIN بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"لقد كتبت كلمة المرور بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"لقد رسمت نقش فتح القفل بطريقة غير صحيحة <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانية."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين الجهاز اللوحي على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة ضبط الجهاز اللوحي على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"لقد حاولت فتح قفل جهاز Android TV بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة أخرى غير ناجحة، ستتم إعادة ضبط جهاز Android TV على الإعداد التلقائي للمصنع وسيتم فقدان جميع بيانات المستخدمين."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"لقد حاولت فتح قفل الهاتف بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين الهاتف على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. سيتم الآن إعادة تعيين الجهاز اللوحي على الإعدادات الأساسية."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"لقد حاولت فتح قفل الهاتف بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة ضبط الهاتف على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. سيتم الآن إعادة ضبط الجهاز اللوحي على الإعدادات الأساسية."</string> <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"لقد حاولت فتح قفل جهاز Android TV بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم الآن إعادة ضبط جهاز Android TV على الإعداد التلقائي للمصنع."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"لقد حاولت فتح قفل الهاتف بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. سيتم الآن إعادة تعيين الهاتف على الإعدادات الأساسية."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"لقد حاولت فتح قفل الهاتف بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. سيتم الآن إعادة ضبط الهاتف على الإعدادات الأساسية."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة أخرى غير ناجحة، ستُطالب بإلغاء قفل جهاز Android TV باستخدام حساب بريد إلكتروني.\n\n يُرجى إعادة المحاولة بعد <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string> @@ -1712,8 +1718,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"لن يتم منح إذن الوصول إلى الموقع الجغرافي أثناء الاستخدام للخدمات التي تعمل في المقدّمة من <xliff:g id="PACKAGENAME">%1$s</xliff:g> والتي تبدأ من الخلفية في إصدارات R القادمة. يُرجى مراجعة go/r-bg-fgs-restriction وتقديم تقرير خطأ."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"هل تريد رفع مستوى الصوت فوق المستوى الموصى به؟\n\nقد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"هل تريد استخدام اختصار \"سهولة الاستخدام\"؟"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"عند تفعيل الاختصار، يؤدي الضغط على زرّي التحكّم في مستوى الصوت معًا لمدة 3 ثوانٍ إلى تفعيل إحدى ميزات إمكانية الوصول."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"تعديل الاختصارات"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"إلغاء"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"إيقاف الاختصار"</string> @@ -1859,12 +1864,12 @@ <string name="package_installed_device_owner" msgid="7035926868974878525">"تم التثبيت بواسطة المشرف"</string> <string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string> - <string name="confirm_battery_saver" msgid="5247976246208245754">"موافق"</string> + <string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string> <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string> <string name="battery_saver_description" msgid="7618492104632328184">"لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"."</string> <string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيق الذي تستخدمه الآن الوصول إلى البيانات، ولكن لا يمكنه تنفيذ ذلك كثيرًا. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string> - <string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تشغيل توفير البيانات؟"</string> - <string name="data_saver_enable_button" msgid="4399405762586419726">"تشغيل"</string> + <string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تفعيل توفير البيانات؟"</string> + <string name="data_saver_enable_button" msgid="4399405762586419726">"تفعيل"</string> <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273"> <item quantity="zero">لمدة أقل من دقيقة (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> <item quantity="two">لمدة دقيقتين (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item> @@ -1976,6 +1981,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"غير مصنفة"</string> <string name="importance_from_user" msgid="2782756722448800447">"لقد عيَّنت أهمية هذه الإشعارات."</string> <string name="importance_from_person" msgid="4235804979664465383">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> (يوجد مستخدم بهذا الحساب مسبقًا)؟"</string> <string name="user_creation_adding" msgid="7305185499667958364">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> ؟"</string> <string name="language_selection_title" msgid="52674936078683285">"إضافة لغة"</string> @@ -1991,11 +1998,11 @@ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"استئناف تشغيل التطبيق"</string> <string name="work_mode_off_title" msgid="5503291976647976560">"تفعيل الملف الشخصي للعمل؟"</string> <string name="work_mode_off_message" msgid="8417484421098563803">"سيتم تفعيل تطبيقات العمل التي تستخدمها والإشعارات والبيانات وغيرها من ميزات الملف الشخصي للعمل"</string> - <string name="work_mode_turn_on" msgid="3662561662475962285">"تشغيل"</string> + <string name="work_mode_turn_on" msgid="3662561662475962285">"تفعيل"</string> <string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string> <string name="app_blocked_message" msgid="542972921087873023">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> غير متاح الآن."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"تمّ إنشاء هذا التطبيق لإصدار قديم من Android وقد لا يعمل بشكل صحيح. جرِّب البحث عن تحديثات أو الاتصال بمطوّر البرامج."</string> - <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"البحث عن إعادة تحميل"</string> + <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"البحث عن تحديث"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"لديك رسائل جديدة"</string> <string name="new_sms_notification_content" msgid="3197949934153460639">"فتح تطبيق الرسائل القصيرة SMS للعرض"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"قد تكون بعض الوظائف مُقيّدة."</string> @@ -2010,7 +2017,7 @@ <string name="app_info" msgid="6113278084877079851">"معلومات عن التطبيق"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"جارٍ بدء العرض التوضيحي…"</string> - <string name="demo_restarting_message" msgid="1160053183701746766">"جارٍ إعادة تعيين الجهاز…"</string> + <string name="demo_restarting_message" msgid="1160053183701746766">"جارٍ إعادة ضبط الجهاز…"</string> <string name="suspended_widget_accessibility" msgid="6331451091851326101">"تم إيقاف <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="conference_call" msgid="5731633152336490471">"مكالمة جماعية"</string> <string name="tooltip_popup_title" msgid="7863719020269945722">"تلميح"</string> @@ -2048,15 +2055,15 @@ <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"هل تريد حفظ <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> في "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"؟"</string> <string name="autofill_save_title_with_3types" msgid="6598228952100102578">"هل تريد حفظ <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> و<xliff:g id="TYPE_2">%3$s</xliff:g> في "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"؟"</string> <string name="autofill_update_title" msgid="3630695947047069136">"هل تريد التحديث في "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"؟"</string> - <string name="autofill_update_title_with_type" msgid="5264152633488495704">"هل تريد إعادة تحميل <xliff:g id="TYPE">%1$s</xliff:g> في "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"؟"</string> - <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"هل تريد إعادة تحميل <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> في "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"؟"</string> - <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"هل تريد إعادة تحميل هذه العناصر في "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> و<xliff:g id="TYPE_2">%3$s</xliff:g>؟"</string> + <string name="autofill_update_title_with_type" msgid="5264152633488495704">"هل تريد تحديث <xliff:g id="TYPE">%1$s</xliff:g> في "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"؟"</string> + <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"هل تريد تحديث <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> في "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"؟"</string> + <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"هل تريد تحديث هذه العناصر في "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> و<xliff:g id="TYPE_2">%3$s</xliff:g>؟"</string> <string name="autofill_save_yes" msgid="8035743017382012850">"حفظ"</string> <string name="autofill_save_no" msgid="9212826374207023544">"لا، شكرًا"</string> <string name="autofill_save_notnow" msgid="2853932672029024195">"ليس الآن"</string> <string name="autofill_save_never" msgid="6821841919831402526">"أبدًا"</string> <string name="autofill_update_yes" msgid="4608662968996874445">"تعديل"</string> - <string name="autofill_continue_yes" msgid="7914985605534510385">"مواصلة"</string> + <string name="autofill_continue_yes" msgid="7914985605534510385">"متابعة"</string> <string name="autofill_save_type_password" msgid="5624528786144539944">"كلمة مرور"</string> <string name="autofill_save_type_address" msgid="3111006395818252885">"عنوان"</string> <string name="autofill_save_type_credit_card" msgid="3583795235862046693">"بطاقة ائتمان"</string> @@ -2157,20 +2164,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصي"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"عمل"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"تتعذّر المشاركة مع تطبيقات العمل"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"تتعذّر المشاركة مع التطبيقات الشخصية"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"حظر مشرف تكنولوجيا المعلومات لديك المشاركة بين التطبيقات الشخصية وتطبيقات العمل."</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"تشغيل تطبيقات العمل"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"تشغيل تطبيقات العمل للوصول إلى تطبيقات العمل وجهات الاتصال"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ليس هناك تطبيقات متاحة"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"تعذّر العثور على أي تطبيقات"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"تفعيل الملف الشخصي للعمل"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"تسجيل الصوت أو تشغيله في المكالمات الهاتفية"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"يسمح الإذن لهذا التطبيق بتسجيل الصوت أو تشغيله في المكالمات الهاتفية عندما يتم تخصيصه كالتطبيق التلقائي لبرنامج الاتصال."</string> </resources> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 9b42cf2b340d..b646b4065c78 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"আপোনাৰ প্ৰতিষ্ঠানটোৱে এই ডিভাইচটো পৰিচালনা কৰে আৰু ই নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ কৰিব পাৰে। সবিশেষ জানিবলৈ টিপক।"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"আপোনাৰ প্ৰশাসকে অৱস্থানৰ ছেটিংসমূহ সলনি কৰিছে"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"আপোনাৰ অৱস্থানৰ ছেটিংসমূহ চাবলৈ টিপক।"</string> + <string name="country_detector" msgid="7023275114706088854">"দেশ চিনাক্তকাৰী"</string> + <string name="location_service" msgid="2439187616018455546">"অৱস্থান সেৱা"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"ছেন্সৰ জাননী সেৱা"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight সেৱা"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string> <string name="factory_reset_message" msgid="2657049595153992213">"এই প্ৰশাসক এপটো ব্যৱহাৰ কৰিব নোৱাৰি। এতিয়া আপোনাৰ ডিভাইচটোৰ ডেটা মচা হ\'ব।\n\nআপোনাৰ কিবা প্ৰশ্ন থাকিলে আপোনাৰ প্ৰতিষ্ঠানৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"প্ৰিণ্ট কৰা কাৰ্য <xliff:g id="OWNER_APP">%s</xliff:g>এ অক্ষম কৰি ৰাখিছে।"</string> @@ -245,6 +249,10 @@ <item quantity="one">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item> <item quantity="other">ত্ৰুটি সম্পর্কীয় অভিযোগৰ বাবে <xliff:g id="NUMBER_1">%d</xliff:g>ছেকেণ্ডৰ ভিতৰত স্ক্ৰীণশ্বট লোৱা হ\'ব।</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"নিঃশব্দ ম\'ড"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ধ্বনি অফ আছে"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ধ্বনি অন আছে"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"আকৌ চেষ্টা কৰক।"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনো ফিংগাৰপ্ৰিণ্ট যোগ কৰা নহ\'ল।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> আঙুলি"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"মুখমণ্ডল সত্যাপন কৰিব পৰা নগ’ল। আকৌ চেষ্টা কৰক।"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"আপুনি মুখাৱয়বৰদ্বাৰা আনলক কৰাটো ছেট আপ কৰা নাই।"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইচটোত মুখাৱয়বৰদ্বাৰা আনলক কৰা সুবিধাটো নচলে।"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string> <string name="face_name_template" msgid="3877037340223318119">"মুখমণ্ডল <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"ইউএছবি ডিবাগিং সংযোগ কৰা হ’ল"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"ইউএছবি ডিবাগিং বন্ধ কৰিবলৈ টিপক"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"ইউএছবি ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ৱায়াৰলেছ ডিবাগিং সংযোগ কৰা হৈছে"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ৱায়াৰলেছ ডিবাগিং অফ কৰিবলৈ টিপক"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ৱায়াৰলেছ ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"টেষ্ট হাৰনেছ ম’ড সক্ষম কৰা আছে"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"টেষ্ট হাৰনেছ ম’ড অক্ষম কৰিবলৈ ফেক্টৰী ৰিছেট কৰক।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ক্ৰমিক কনছ’ল সক্ষম কৰা আছে"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"নেপথ্যই <xliff:g id="PACKAGENAME">%1$s</xliff:g>ৰ পৰা আৰম্ভ কৰা অগ্ৰভূমিৰ সেৱাটোৰ ভৱিষ্যতৰ R বিল্ডসমূহত ব্যৱহাৰ হৈ থকা সম্পৰ্কীয় অনুমতি নাথাকিব। অনুগ্ৰহ কৰি go/r-bg-fgs-restriction চাওক আৰু এটা বাগৰিপ\'ৰ্ট ফাইল কৰক।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"অনুমোদিত স্তৰতকৈ ওপৰলৈ ভলিউম বঢ়াব নেকি?\n\nদীৰ্ঘ সময়ৰ বাবে উচ্চ ভলিউমত শুনাৰ ফলত শ্ৰৱণ ক্ষমতাৰ ক্ষতি হ\'ব পাৰে।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"দিব্যাংগসকলৰ সুবিধাৰ শ্বৰ্টকাট ব্যৱহাৰ কৰেনে?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শ্বৰ্টকাটটো অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটাম ৩ ছেকেণ্ডৰ বাবে হেঁচি ধৰি ৰাখিলে এটা সাধ্য সুবিধা আৰম্ভ হ’ব।"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"শ্বৰ্টকাটসমূহ সম্পাদনা কৰক"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"বাতিল কৰক"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শ্বৰ্টকাট অফ কৰক"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"শ্ৰেণীবদ্ধ নকৰা"</string> <string name="importance_from_user" msgid="2782756722448800447">"এই জাননীবোৰৰ গুৰুত্ব আপুনি ছেট কৰব লাগিব।"</string> <string name="importance_from_person" msgid="4235804979664465383">"এই কার্যৰ সৈতে জড়িত থকা লোকসকলক ভিত্তি কৰি এইয়া গুৰুত্বপূর্ণ বুলি বিবেচনা কৰা হৈছ।"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ (এই একাউণ্টটোৰ এজন ব্যৱহাৰকাৰী ইতিমধ্যে আছে) জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string> <string name="language_selection_title" msgid="52674936078683285">"ভাষা যোগ কৰক"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"কৰ্মস্থান"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"কৰ্মস্থানৰ এপ্সমূহৰ সৈতে শ্বেয়াৰ কৰিব নোৱাৰি"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ব্যক্তিগত এপ্সমূহৰ সৈতে শ্বেয়াৰ কৰিব নোৱাৰি"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"আপোনাৰ আইটি প্ৰশাসকে ব্যক্তিগত আৰু কৰ্মস্থানৰ এপ্সমূহৰ মাজত সমল শ্বেয়াৰ কৰাটো অৱৰোধ কৰিছে"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"কৰ্মস্থানৰ এপ্সমূহ অন কৰক"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"কৰ্মস্থানৰ এপ্ আৰু সম্পৰ্কসমূহ এক্সেছ কৰিবলৈ কৰ্মস্থানৰ এপ্সমূহ অন কৰক"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"কোনো এপ্ উপলব্ধ নহয়"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"আমি কোনো এপ্ বিচাৰি নাপালোঁ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"কৰ্মস্থানৰ প্ৰ’ফাইল অন কৰক"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"টেলিফ’নী কলসমূহত অডিঅ’ ৰেকৰ্ড অথবা প্লে’ কৰক"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ডিফ’ল্ট ডায়েলাৰ এপ্লিকেশ্বন হিচাপে আবণ্টন কৰিলে, এই এপ্টোক টেলিফ’নী কলসমূহত অডিঅ’ ৰেকৰ্ড অথবা প্লে’ কৰিবলৈ অনুমতি দিয়ে।"</string> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 73adbd86385f..fe5e4cf34484 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Təşkilat bu cihazı idarə edir və şəbəkənin ötürülməsinə nəzarət edə bilər. Detallar üçün klikləyin."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Məkan ayarları admininiz tərəfindən dəyişildi"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Məkan ayarlarınıza baxmaq üçün toxunun."</string> + <string name="country_detector" msgid="7023275114706088854">"Ölkə Aşkarlayıcısı"</string> + <string name="location_service" msgid="2439187616018455546">"Məkan Xidməti"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Bildiriş Xidməti"</string> + <string name="twilight_service" msgid="8964898045693187224">"Alaqaranlıq Xidməti"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Admin tətbiqini istifadə etmək mümkün deyil. Cihaz indi təmizlənəcək.\n\nSualınız varsa, təşkilatın admini ilə əlaqə saxlayın."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Çap <xliff:g id="OWNER_APP">%s</xliff:g> tərəfindən deaktiv edildi."</string> @@ -245,6 +249,10 @@ <item quantity="other">Baq hesabatı üçün <xliff:g id="NUMBER_1">%d</xliff:g> saniyədə sktinşot çəkilir.</item> <item quantity="one">Baq hesabatı üçün <xliff:g id="NUMBER_0">%d</xliff:g> saniyədə skrinşot çəkilir.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Səssiz rejim"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Səs qapalıdır"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Səs Aktivdir"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Yenidən cəhd edin."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Barmaq izi qeydə alınmayıb."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor müvəqqəti deaktivdir."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Üz doğrulanmadı. Yenidən cəhd edin."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Üz kilidi quraşdırmamısınız."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Üz kilidi bu cihazda dəstəklənmir."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor müvəqqəti deaktivdir."</string> <string name="face_name_template" msgid="3877037340223318119">"Üz <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB sazlama qoşuludur"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB sazlamanı deaktiv etmək üçün klikləyin"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USb debaqı deaktivasiya etməyi seçin."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Simsiz sazlama qoşulub"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Simsiz sazlamanı deaktiv etmək üçün toxunun"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Simsiz sazlamanı deaktiv etmək üçün seçin."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Rejimi aktivdir"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Test Rejimini deaktiv etmək üçün fabrika ayarlarına sıfırlayın."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Ardıcıl konsol aktiv edildi"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Arxa fonda başladılan <xliff:g id="PACKAGENAME">%1$s</xliff:g> üzrə ön plan xidmətinin gələcək R versiyalarında \"istifadə zamanı\" icazəsi olmayacaq. go/r-bg-fgs-restriction bölməsinə keçin və baq hesabatı göndərin."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Səsin həcmi tövsiyə olunan səviyyədən artıq olsun?\n\nYüksək səsi uzun zaman dinləmək eşitmə qabiliyyətinizə zərər vura bilər."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Əlçatımlılıq Qısayolu istifadə edilsin?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Qısayol aktiv olduqda, hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası başladılacaq."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Qısayolları redaktə edin"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Ləğv edin"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Qısayolu Deaktiv edin"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Kateqoriyasız"</string> <string name="importance_from_user" msgid="2782756722448800447">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string> <string name="importance_from_person" msgid="4235804979664465383">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> (artıq bu hesabı olan İstifadəçi mövcuddur) ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> ilə yeni İstifadəçi yartmağa icazə verilsin?"</string> <string name="language_selection_title" msgid="52674936078683285">"Dil əlavə edin"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Şəxsi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"İş tətbiqləri ilə paylaşmaq olmur"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Şəxsi tətbiqlərlə paylaşmaq olmur"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"İT admininiz şəxsi və iş tətbiqləri arasında paylaşımı bloklayıb"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"İş tətbiqlərini aktiv edin"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"İş tətbiqləri və kontaktlara giriş üçün iş tətbiqlərini aktiv edin"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Heç bir tətbiq əlçatan deyil"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Heç bir tətbiq tapılmadı"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"İş profilini aktiv edin"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefon zənglərində audio yazmaq və ya oxutmaq"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Defolt nömrəyığan tətbiq kimi təyin edildikdə, bu tətbiqə telefon zənglərində audio yazmaq və ya oxutmaq üçün icazə verir."</string> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index bf250f78e51d..528b11b9ff0d 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -195,6 +195,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizacija upravlja ovim uređajem i može da nadgleda mrežni saobraćaj. Dodirnite za detalje."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Administrator je promenio podešavanja lokacije"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Dodirnite da biste videli podešavanja lokacije."</string> + <string name="country_detector" msgid="7023275114706088854">"Detektor zemlje"</string> + <string name="location_service" msgid="2439187616018455546">"Usluga lokacije"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Usluga obaveštenja senzora"</string> + <string name="twilight_service" msgid="8964898045693187224">"Usluga Sumrak"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, kontaktirajte administratora organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -248,6 +252,10 @@ <item quantity="few">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item> <item quantity="other">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Nečujni režim"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je ISKLJUČEN"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je UKLJUČEN"</string> @@ -549,8 +557,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probajte ponovo."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registrovan nijedan otisak prsta."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +601,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Provera lica nije uspela. Probajte ponovo."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Niste podesili otključavanje licem"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string> <string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1338,6 +1344,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Otklanjanje grešaka sa USB-a je omogućeno"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Dodirnite da biste isključili otklanjanje grešaka sa USB-a"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Izaberite da biste onemogućili otklanjanja grešaka sa USB-a."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Bežično otklanjanje grešaka je povezano"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Dodirnite da biste isključili bežično otklanjanje grešaka"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Izaberite da biste onemogućili bežično otklanjanje grešaka."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Omogućen je režim probnog korišćenja"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Obavite resetovanje na fabrička podešavanja da biste onemogućili režim probnog korišćenja."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serijska konzola je omogućena"</string> @@ -1643,8 +1652,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluga u prvom planu sa <xliff:g id="PACKAGENAME">%1$s</xliff:g> koja je pokrenuta u pozadini neće imati dozvolu tokom korišćenja u budućim R verzijama. Posetite go/r-bg-fgs-restriction i pošaljite izveštaj o grešci."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li da koristite prečicu za pristupačnost?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Izmenite prečice"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečicu"</string> @@ -1877,6 +1885,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Nekategorizovano"</string> <string name="importance_from_user" msgid="2782756722448800447">"Vi podešavate važnost ovih obaveštenja."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ovo je važno zbog ljudi koji učestvuju."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik sa tim nalogom već postoji)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string> @@ -2052,20 +2062,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Lični"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Poslovni"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ne možete da delite sadržaj sa aplikacijama za posao"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ne možete da delite sadržaj sa ličnim aplikacijama"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT administrator je blokirao deljenje između ličnih aplikacija i aplikacija za posao"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Uključite aplikacije za posao"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Uključite aplikacije za posao da biste pristupili aplikacijama i kontaktima za posao"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nema dostupnih aplikacija"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nismo pronašli nijednu aplikaciju"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Uključi profil za Work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snimanje ili puštanje zvuka u telefonskim pozivima"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Omogućava ovoj aplikaciji, kada je dodeljena kao podrazumevana aplikacija za pozivanje, da snima ili pušta zvuk u telefonskim pozivima."</string> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 454a21e1f719..1303126cacb7 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша арганізацыя кіруе гэтай прыладай і можа сачыць за сеткавым трафікам. Дакраніцеся для атрымання дадатковай інфармацыі."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Налады месцазнаходжання зменены адміністратарам"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Націсніце, каб праглядзець налады месцазнаходжання."</string> + <string name="country_detector" msgid="7023275114706088854">"Дэтэктар краіны"</string> + <string name="location_service" msgid="2439187616018455546">"Служба геалакацыі"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Служба апавяшчэнняў датчыка"</string> + <string name="twilight_service" msgid="8964898045693187224">"Служба Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Немагчыма выкарыстоўваць праграму адміністравання. Звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -251,6 +255,10 @@ <item quantity="many">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунд.</item> <item quantity="other">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунды.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Бязгучны рэжым"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Гук выкл."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Гук уключаны"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Паспрабуйце яшчэ раз."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Не ўдалося спраўдзіць твар. Паўтарыце спробу."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Вы не наладзілі распазнаванне твару."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"На гэтай прыладзе распазнаванне твару не падтрымліваецца."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчык часова выключаны."</string> <string name="face_name_template" msgid="3877037340223318119">"Твар <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Адладка па USB падключана"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Націсніце, каб выключыць адладку па USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Выберыце, каб адключыць адладку USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Бесправадная адладка падключана"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Націсніце, каб выключыць бесправадную адладку"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Выберыце, каб адключыць бесправадную адладку."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Тэставы рэжым уключаны"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Каб выключыць тэставы рэжым, скіньце налады да заводскіх значэнняў."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Паслядоўная кансоль уключана"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Запушчаны ў фонавым рэжыме асноўны сэрвіс з пакета \"<xliff:g id="PACKAGENAME">%1$s</xliff:g>\" не будзе мець дазволу while-in-use у будучых зборках на мове R. Наведайце сайт go/r-bg-fgs-restriction і адпраўце справаздачу пра памылку."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Выкарыстоўваць камбінацыю хуткага доступу для спецыяльных магчымасцей?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Калі хуткі доступ уключаны, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб запусціць функцыю спецыяльных магчымасцей."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Змяніць ярлыкі"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Скасаваць"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Дэактываваць камбінацыю хуткага доступу"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Некатэгарызаванае"</string> <string name="importance_from_user" msgid="2782756722448800447">"Вы задалі важнасць гэтых апавяшчэнняў."</string> <string name="importance_from_person" msgid="4235804979664465383">"Гэта важна, бо з гэтым звязаны пэўныя людзі."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g> (Карыстальнік з гэтым уліковым запісам ужо існуе)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Дадаць мову"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Асабістыя"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Працоўныя"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Не ўдалося абагуліць з працоўнымі праграмамі"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Не ўдалося абагуліць з асабістымі праграмамі"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ваш ІТ-адміністратар заблакіраваў абагульванне паміж асабістымі і працоўнымі праграмамі"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Уключыце працоўныя праграмы"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Уключыце працоўныя праграмы, каб мець доступ да іх і да кантактаў"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Няма даступных праграм"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Нам не ўдалося знайсці ніводнай праграмы"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Пераключыцца на працоўны профіль"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Запісваць або прайграваць аўдыя ў тэлефонных выкліках"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Дазваляе гэтай праграме (калі яна наладжана ў якасці стандартнага набіральніка нумара) запісваць або прайграваць аўдыя ў тэлефонных выкліках."</string> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index ad8fdc683a89..33e59aa20dab 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Организацията ви управлява това устройство и може да наблюдава мрежовия трафик. Докоснете за подробности."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Настройките за местоположението са променени от администратора ви"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Докоснете, за да видите настройките за местоположението."</string> + <string name="country_detector" msgid="7023275114706088854">"Инструмент за установяване на държавата"</string> + <string name="location_service" msgid="2439187616018455546">"Услуга за местоположението"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Услуга за известия за сензорите"</string> + <string name="twilight_service" msgid="8964898045693187224">"Услуга Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Екранната снимка за сигнала за програмна грешка ще бъде направена след <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item> <item quantity="one">Екранната снимка за сигнала за програмна грешка ще бъде направена след <xliff:g id="NUMBER_0">%d</xliff:g> секунда.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Тих режим"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Звукът е ИЗКЛЮЧЕН"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Звукът е ВКЛЮЧЕН"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Опитайте отново."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Няма регистрирани отпечатъци."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорът е временно деактивиран."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Пръст <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Лицето не може да се потвърди. Опитайте отново."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Не сте настроили отключването с лице."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Отключването с лице не се поддържа на това устройство."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорът е временно деактивиран."</string> <string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Отстраняване на грешки през USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Докоснете, за да изключите"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Изберете, за да деактивирате отстраняването на грешки през USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Функцията за безжично отстраняване на грешки е свързана"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Докоснете, за да изключите безжичното отстраняване на грешки"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Изберете, за да деактивирате безжичното отстраняване на грешки."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Режимът за тестова среда е активиран"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Възстановете фабричните настройки, за да деактивирате режима за тестова среда."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Серийната конзола е активирана"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Задният план, който е стартирал услуга на преден план от <xliff:g id="PACKAGENAME">%1$s</xliff:g>, няма да има разрешение при използване в бъдещите компилации R. Моля, вижте go/r-bg-fgs-restriction и подайте сигнал за програмна грешка."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да се увеличи ли силата на звука над препоръчителното ниво?\n\nПродължителното слушане при висока сила на звука може да увреди слуха ви."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Искате ли да използвате пряк път към функцията за достъпност?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за силата на звука и ги задържите за 3 секунди."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редактиране на преките пътища"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Отказ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Изключване на прекия път"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Некатегоризирани"</string> <string name="importance_from_user" msgid="2782756722448800447">"Зададохте важността на тези известия."</string> <string name="importance_from_person" msgid="4235804979664465383">"Това е важно заради участващите хора."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g> (вече съществува потребител с този профил)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Добавяне на език"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Служебни"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Споделянето със служебни приложения не е възможно"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Споделянето с лични приложения не е възможно"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Системният ви администратор е блокирал споделянето между лични и служебни приложения"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Включете служебните приложения"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Включете служебните приложения, за да имате достъп до тях и служебните контакти"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Няма приложения"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Не успяхме да намерим приложения"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Включване на служебния потребителски профил"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Записване или възпроизвеждане на аудио при телефонни обаждания"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Дава възможност на това приложение да записва или възпроизвежда аудио при телефонни обаждания, когато е зададено като основно приложение за набиране."</string> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index f5570c66f748..386c303338cc 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -191,10 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"ব্যক্তিগত কাজের জন্য অ্যাডমিন এই ডিভাইস ব্যবহার করার অনুমতি দেয়নি"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ডিভাইসটি পরিচালনা করা হচ্ছে"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"আপনার প্রতিষ্ঠান এই ডিভাইসটি পরিচালনা করে এবং এটির নেটওয়ার্ক ট্রাফিকের উপরে নজর রাখতে পারে। বিশদ বিবরণের জন্য ট্যাপ করুন।,"</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"আপনার অ্যাডমিন লোকেশন সেটিংস পরিবর্তন করেছেন"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"আপনার লোকেশন সেটিংস দেখার জন্য ট্যাপ করুন।"</string> + <string name="country_detector" msgid="7023275114706088854">"দেশ শনাক্তকারী"</string> + <string name="location_service" msgid="2439187616018455546">"লোকেশন পরিষেবা"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"সেন্সর বিজ্ঞপ্তি পরিষেবা"</string> + <string name="twilight_service" msgid="8964898045693187224">"গোধূলি পরিষেবা"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string> <string name="factory_reset_message" msgid="2657049595153992213">"অ্যাডমিন অ্যাপটি ব্যবহার করা যাবে না। আপনার ডিভাইসে থাকা সবকিছু এখন মুছে ফেলা হবে।\n\nকোনও প্রশ্ন থাকলে আপনার প্রতিষ্ঠানের অ্যাডমিনের সাথে যোগাযোগ করুন।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> প্রিন্টিং বন্ধ রেখেছে।"</string> @@ -247,6 +249,10 @@ <item quantity="one"><xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে ত্রুটির প্রতিবেদনের জন্য স্ক্রিনশট নেওয়া হচ্ছে৷</item> <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে ত্রুটির প্রতিবেদনের জন্য স্ক্রিনশট নেওয়া হচ্ছে৷</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"নীরব মোড"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"শব্দ বন্ধ করা আছে"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"শব্দ চালু করা আছে"</string> @@ -433,8 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"এই প্রিভিলিজ | সিস্টেম অ্যাপটি যেকোনও সময়ে সিস্টেম ক্যামেরা ব্যবহার করে ছবি তুলতে এবং ভিডিও রেকর্ড করতে পারবে। এর জন্য অ্যাপের Android.permission.CAMERA -এর অনুমতি প্রয়োজন"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"ভাইব্রেশন নিয়ন্ত্রণ করুন"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"ভাইব্রেট করার স্থিতি অ্যাক্সেস করার অনুমতি দিন।"</string> <string name="permlab_callPhone" msgid="1798582257194643320">"সরাসরি ফোন নম্বরগুলিতে কল করে"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক পেমেন্ট করতে হতে পারে৷"</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS পরিষেবাতে অ্যাক্সেস"</string> @@ -549,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"আবার চেষ্টা করুন৷"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনও আঙ্গুলের ছাপ নথিভুক্ত করা হয়নি।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"আঙ্গুল <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"আপনার মুখ যাচাই করা যাচ্ছে না। আবার চেষ্টা করুন।"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"এখনও মুখের সাহায্যে আনলক করার সুবিধা সেট-আপ করেননি।"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইসে মুখের সাহায্যে আনলক করার সুবিধাটি কাজ করে না।"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> ফেস"</string> <string-array name="face_error_vendor"> </string-array> @@ -1321,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ডিবাগিং কানেক্ট হয়েছে"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"ইউএসবি ডিবাগিং বন্ধ করতে ট্যাপ করুন"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ডিবাগিং অক্ষম করতে বেছে নিন।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ওয়্যারলেস ডিবাগিং কানেক্ট করা হয়েছে"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ওয়্যারলেস ডিবাগিং বন্ধ করতে ট্যাপ করুন"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ওয়্যারলেস ডিবাগিং বন্ধ করতে বেছে নিন।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"টেস্ট হারনেস মোড চালু আছে"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"টেস্ট হারনেস মোড বন্ধ করতে ফ্যাক্টরি রিসেট করুন।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"সিরিয়াল কনসোল চালু করা হয়েছে"</string> @@ -1624,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> থেকে শুরু হওয়া ফোরগ্রাউন্ড পরিষেবাটির ভবিষ্যতে আর বিল্ডগুলিতে ব্যবহারের অনুমতি নেই। go/r-bg-fgs-restriction দেখুন এবং বাগরিপোর্ট জমা দিন।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"প্রস্তাবিত স্তরের চেয়ে বেশি উঁচুতে ভলিউম বাড়াবেন?\n\nউঁচু ভলিউমে বেশি সময় ধরে কিছু শুনলে আপনার শ্রবনশক্তির ক্ষতি হতে পারে।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"অ্যাক্সেসযোগ্যতা শর্টকাট ব্যবহার করবেন?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শর্টকাট চালু করা থাকাকালীন দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি ফিচার চালু হবে।"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"শর্টকাট এডিট করুন"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"বাতিল করুন"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"শর্টকাট বন্ধ করুন"</string> @@ -1848,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"বিভাগ নির্ধারিত নয়"</string> <string name="importance_from_user" msgid="2782756722448800447">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string> <string name="importance_from_person" msgid="4235804979664465383">"লোকজন জড়িত থাকার কারণে এটি গুরুত্বপূর্ণ।"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g>-এ (একজন ব্যবহারকারী এই অ্যাকাউন্টে আগে থেকেই রয়েছেন) একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি <xliff:g id="APP">%1$s</xliff:g>-কে দেবেন?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g>-এ একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি <xliff:g id="APP">%1$s</xliff:g>-কে দেবেন?"</string> <string name="language_selection_title" msgid="52674936078683285">"একটি ভাষা যোগ করুন"</string> @@ -2021,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"অফিস"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"অফিস অ্যাপের সাথে শেয়ার করা যাচ্ছে না"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ব্যক্তিগত অ্যাপের সাথে শেয়ার করা যাচ্ছে না"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"আপনার IT অ্যাডমিন ব্যক্তিগত ও অফিস অ্যাপের মধ্যে শেয়ার করা ব্লক করে রেখেছেন"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"অফিসের অ্যাপ চালু করুন"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"অফিসের অ্যাপ ও পরিচিতি অ্যাক্সেস করার জন্য অফিসের অ্যাপ চালু করুন"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"কোনও অ্যাপ উপলভ্য নেই"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"কোনও অ্যাপ খুঁজে পাওয়া যায়নি"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"অফিস প্রোফাইল চালু করুন"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"টেলিফোন কলে অডিও রেকর্ড বা প্লে করুন"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ডিফল্ট ডায়ালার অ্যাপ্লিকেশন হিসেবে বেছে নেওয়া হলে, টেলিফোন কলে অডিও রেকর্ড বা প্লে করার জন্য এই অ্যাপকে অনুমতি দেয়।"</string> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index fd53b69a61a1..743e8c4fb4ba 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -193,8 +193,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administrator je ustupio uređaj za ličnu upotrebu"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja."</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može pratiti mrežni saobraćaj. Dodirnite za detalje."</string> - <string name="location_changed_notification_title" msgid="4119726617105166830">"Postavke lokacije je promijenio vaš administrator"</string> + <string name="location_changed_notification_title" msgid="4119726617105166830">"Administrator je promijenio postavke lokacije"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Dodirnite da vidite postavke lokacije."</string> + <string name="country_detector" msgid="7023275114706088854">"Detektor zemlje"</string> + <string name="location_service" msgid="2439187616018455546">"Usluga lokacije"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Usluga obavještavanja putem senzora"</string> + <string name="twilight_service" msgid="8964898045693187224">"Usluga Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nije moguće koristiti aplikaciju administratora. Potpuno će se izbrisati podaci na vašem uređaju.\n\nAko imate pitanja, obratite se administratoru svoje organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -248,6 +252,10 @@ <item quantity="few">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item> <item quantity="other">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Nečujni način rada"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je isključen"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je uključen"</string> @@ -549,8 +557,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Pokušajte ponovo."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije prijavljen nijedan otisak prsta."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +601,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nije moguće potvrditi lice. Pokušajte ponovo."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Niste postavili otključavanje licem."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string> <string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1340,6 +1346,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Otklanjanje grešaka putem USB-a je uspostavljeno"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Dodirnite da isključite otklanjanje grešaka putem USB-a"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Odaberite da onemogućite ispravljanje grešaka koristeći USB"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Bežično otklanjanje grešaka je povezano"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Dodirnite da isključite bežično otklanjanje grešaka"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Odaberite da onemogućite bežično otklanjanje grešaka."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Omogućen način rada okvira za testiranje"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Izvršite vraćanje na fabričke postavke da onemogućite način rada okvira za testiranje."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serijska konzola omogućena"</string> @@ -1645,8 +1654,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluge iz prvog plana započete u pozadini s web lokacije <xliff:g id="PACKAGENAME">%1$s</xliff:g> neće imati odobrenje za funkciju \"za vrijeme korištenja\" u budućim R verzijama. Pogledajte go/r-bg-fgs-restriction i podnesite izvještaj o greškama."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritiskom i držanjem oba dugmeta za jačinu zvuka u trajanju od 3 sekunde pokrenut će se funkcija pristupačnosti."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi prečice"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečicu"</string> @@ -1879,6 +1887,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Nije kategorizirano"</string> <string name="importance_from_user" msgid="2782756722448800447">"Vi određujete značaj ovih obavještenja."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ovo je značajno zbog osoba koje su uključene."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Dodajte jezik"</string> @@ -2054,20 +2064,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Lično"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nije moguće dijeliti s poslovnim aplikacijama"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nije moguće dijeliti s ličnim aplikacijama"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Vaš IT administrator je blokirao dijeljenje između ličnih i poslovnih aplikacija"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Uključite poslovne aplikacije"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Uključite poslovne aplikacije da pristupite poslovnim aplikacijama i kontaktima"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nema dostupnih aplikacija"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nismo pronašli nijednu aplikaciju"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Prebaci na radni"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snimanje ili reproduciranje zvuka u telefonskim pozivima"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Kad je ova aplikacija postavljena kao zadana aplikacija za pozivanje, omogućava joj snimanje ili reproduciranje zvuka u telefonskim pozivima."</string> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index fdb8f4584b95..481cafd3f245 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"La teva organització gestiona aquest dispositiu i és possible que supervisi el trànsit de xarxa. Toca per obtenir més informació."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"L\'administrador ha modificat la configuració d\'ubicació"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Toca per veure la configuració d\'ubicació."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector de país"</string> + <string name="location_service" msgid="2439187616018455546">"Servei d\'ubicació"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Servei de notificacions de sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Servei Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No es pot utilitzar l\'aplicació d\'administració. S\'esborraran les dades del dispositiu.\n\nSi tens cap dubte, contacta amb l\'administrador de la teva organització."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha desactivat la impressió."</string> @@ -245,6 +249,10 @@ <item quantity="other">Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons.</item> <item quantity="one">Es farà una captura de pantalla de l\'informe d\'errors d\'aquí a <xliff:g id="NUMBER_0">%d</xliff:g> segon.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silenciós"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"So desactivat"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"El so està activat"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Torna-ho a provar."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No s\'ha registrat cap empremta digital."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes dactilars."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor està desactivat temporalment."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"No es pot verificar la cara. Torna-ho a provar."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"No has configurat el desbloqueig facial"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"El desbloqueig facial no és compatible amb el dispositiu."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor està desactivat temporalment."</string> <string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuració per USB activada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca per desactivar la depuració per USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecciona per desactivar la depuració per USB"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"S\'ha connectat la depuració sense fil"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca per desactivar la depuració sense fil"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecciona per desactivar la depuració sense fil."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"S\'ha activat el mode Agent de prova"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Si vols desactivar el mode Agent de prova, restableix les dades de fàbrica."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"S\'ha activat la consola de sèrie"</string> @@ -1499,7 +1508,7 @@ <string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Comparteix amb <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string> <string name="content_description_sliding_handle" msgid="982510275422590757">"Llisca el dit. Mantén premut."</string> <string name="description_target_unlock_tablet" msgid="7431571180065859551">"Llisca per desbloquejar."</string> - <string name="action_bar_home_description" msgid="1501655419158631974">"Torna a la pàgina d\'inici"</string> + <string name="action_bar_home_description" msgid="1501655419158631974">"Navega fins a la pàgina d\'inici"</string> <string name="action_bar_up_description" msgid="6611579697195026932">"Navega cap amunt"</string> <string name="action_menu_overflow_description" msgid="4579536843510088170">"Més opcions"</string> <string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servei en primer pla (<xliff:g id="PACKAGENAME">%1$s</xliff:g>) iniciat en segon pla no tindrà permís durant l\'ús en compilacions R posteriors. Consulta la pàgina go/r-bg-fgs-restriction i presenta un informe d\'errors."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vols apujar el volum per sobre del nivell recomanat?\n\nSi escoltes música a un volum alt durant períodes llargs, pots danyar-te l\'oïda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vols fer servir la drecera d\'accessibilitat?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si la drecera està activada, prem els dos botons de volum durant 3 segons per iniciar una funció d\'accessibilitat."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edita les dreceres"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancel·la"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactiva la drecera"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sense classificar"</string> <string name="importance_from_user" msgid="2782756722448800447">"Has definit la importància d\'aquestes notificacions."</string> <string name="importance_from_person" msgid="4235804979664465383">"Aquest missatge és important per les persones implicades."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ja hi ha un usuari amb aquest compte.)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Afegeix un idioma"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Feina"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"No es pot compartir amb les aplicacions de treball"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"No es pot compartir amb les aplicacions personals"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"L\'administrador de TI ha bloquejat la compartició entre aplicacions personals i de treball"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa les aplicacions de treball"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa les aplicacions de treball per accedir a aquestes aplicacions i als contactes de feina"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"No hi ha cap aplicació disponible"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"No hem trobat cap aplicació"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activa el perfil de treball"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar o reproduir àudio en trucades"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permet que l\'aplicació gravi o reprodueixi àudio en trucades si està assignada com a aplicació de marcador predeterminada."</string> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a1ff467960a6..8594e1f102b6 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Toto zařízení je spravováno vaší organizací, která může sledovat síťový provoz. Podrobnosti zobrazíte klepnutím."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Administrátor změnil nastavení polohy"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Klepnutím zobrazíte nastavení polohy."</string> + <string name="country_detector" msgid="7023275114706088854">"Detektor země"</string> + <string name="location_service" msgid="2439187616018455546">"Služby určování polohy"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Služba oznámení ze senzoru"</string> + <string name="twilight_service" msgid="8964898045693187224">"Služba detekce soumraku"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikaci pro správu nelze použít. Zařízení teď bude vymazáno.\n\nV případě dotazů vám pomůže administrátor organizace."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Aplikace <xliff:g id="OWNER_APP">%s</xliff:g> tisk zakazuje."</string> @@ -251,6 +255,10 @@ <item quantity="other">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_1">%d</xliff:g> sekund.</item> <item quantity="one">Snímek obrazovky pro zprávu o chybě bude pořízen za <xliff:g id="NUMBER_0">%d</xliff:g> sekundu.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tichý režim"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je VYPNUTÝ."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je zapnutý"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Zkuste to znovu."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nejsou zaregistrovány žádné otisky prstů."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasně deaktivován."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Obličej se nepodařilo ověřit. Zkuste to znovu."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ověření obličejem nemáte nastavené."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Odemknutí obličejem na tomto zařízení není podporováno."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasně deaktivován."</string> <string name="face_name_template" msgid="3877037340223318119">"Obličej <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Ladění přes USB připojeno"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Klepnutím vypnete ladění přes USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Vyberte, chcete-li zakázat ladění přes USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Bezdrátové ladění je připojeno"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Klepnutím vypnete bezdrátové ladění"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Vyberte, chcete-li zakázat bezdrátové ladění."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Režim správce testů je aktivní"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Chcete-li deaktivovat režim správce testů, restartujte zařízení do továrního nastavení."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Je zapnutá sériová konzole"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Služba v popředí z balíčku <xliff:g id="PACKAGENAME">%1$s</xliff:g>, která byla spuštěna na pozadí, v budoucích sestavenách typu R nebude mít oprávnění ke spuštění při používání. Přejděte na adresu go/r-bg-fgs-restriction a vyplňte zprávu o chybě."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšit hlasitost nad doporučenou úroveň?\n\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použít zkratku přístupnosti?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upravit zkratky"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Zrušit"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vypnout zkratku"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Neklasifikováno"</string> <string name="importance_from_user" msgid="2782756722448800447">"Důležitost oznámení určujete vy."</string> <string name="importance_from_person" msgid="4235804979664465383">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Uživatel s tímto účtem již existuje.)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Přidat jazyk"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobní"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Pracovní"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Sdílení s pracovními aplikacemi je zakázáno"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Sdílení s osobními aplikacemi je zakázáno"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Sdílení mezi osobními a pracovními aplikacemi zablokoval váš administrátor IT"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Zapnout pracovní aplikace"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Zapnutím pracovních aplikací získáte přístup k pracovním aplikacím a kontaktům"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Žádné aplikace k dispozici"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nenalezli jsme žádné aplikace"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Zapnout práci"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Záznam a přehrávání zvuků při telefonických hovorech"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Pokud aplikace bude mít toto oprávnění a bude vybrána jako výchozí aplikace pro vytáčení, bude při telefonických hovorech moci přehrávat a zaznamenávat zvuky."</string> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 10da1e72ed26..617bc880b7fc 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se info."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Placeringsindstillinger blev ændret af din administrator"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tryk for at se dine placeringsindstillinger."</string> + <string name="country_detector" msgid="7023275114706088854">"Landeregistrering"</string> + <string name="location_service" msgid="2439187616018455546">"Placeringstjeneste"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Tjenesten Sensor Notification"</string> + <string name="twilight_service" msgid="8964898045693187224">"Tjenesten Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="one">Der tages et screenshot til fejlrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekund.</item> <item quantity="other">Der tages et screenshot til fejlrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Lydløs"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Lyden er slået FRA"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Lyden er TIL"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Prøv igen."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Der er ikke registreret nogen fingeraftryk."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidigt deaktiveret."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ansigtet kan ikke genkendes. Prøv igen."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Du har ikke konfigureret ansigtslås."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansigtslås understøttes ikke på denne enhed."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidigt deaktiveret."</string> <string name="face_name_template" msgid="3877037340223318119">"Ansigt <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-fejlretning er tilsluttet"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tryk for at deaktivere USB-fejlretning"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Vælg for at deaktivere USB-fejlretning."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Der er oprettet forbindelse til trådløs fejlretning"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tryk for at deaktivere trådløs fejlretning"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Vælg for at deaktivere trådløs fejlretning."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Tilstanden Testsele er aktiveret"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Gendan fabriksindstillingerne for at deaktivere tilstanden Testsele."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Seriekonsollen er aktiveret"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Tjenesten i forgrunden fra <xliff:g id="PACKAGENAME">%1$s</xliff:g>, der starter i baggrunden, vil i fremtidige R-builds ikke have tilladelse, mens den er i brug. Se go/r-bg-fgs-restriction, og indsend en fejlrapport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruge genvejen til Hjælpefunktioner?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når genvejen er aktiveret, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediger genveje"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuller"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Deaktiver genvej"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Uden kategori"</string> <string name="importance_from_user" msgid="2782756722448800447">"Du angiver, hvor vigtige disse notifikationer er."</string> <string name="importance_from_person" msgid="4235804979664465383">"Dette er vigtigt på grund af de personer, det handler om."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en nye bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Tilføj et sprog"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Arbejde"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Der kan ikke deles med arbejdsapps"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Der kan ikke deles med personlige apps"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Din it-administrator har blokeret deling mellem personlige apps og arbejdsapps"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktivér arbejdsapps"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktivér arbejdsapps for at få adgang til arbejdsapps og -kontakter"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Ingen tilgængelige apps"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Vi kunne ikke finde nogen apps"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktivér arbejdsprofil"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Optage eller afspille lyd i telefonopkald"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tillader, at denne app kan optage og afspille lyd i telefonopkald, når den er angivet som standardapp til opkald."</string> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 98d9f9228dce..f211b4019eaf 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Deine Organisation verwaltet dieses Gerät und überprüft unter Umständen den Netzwerkverkehr. Tippe hier, um weitere Informationen zu erhalten."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Standorteinstellungen durch Administrator geändert"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tippe, um deine Standorteinstellungen anzuzeigen."</string> + <string name="country_detector" msgid="7023275114706088854">"Country Detector"</string> + <string name="location_service" msgid="2439187616018455546">"Standortdienst"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Die Admin-App kann nicht verwendet werden. Die Daten auf deinem Gerät werden nun gelöscht.\n\nBitte wende dich bei Fragen an den Administrator deiner Organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drucken wurde von <xliff:g id="OWNER_APP">%s</xliff:g> deaktiviert."</string> @@ -245,6 +249,10 @@ <item quantity="other">Screenshot für den Fehlerbericht wird in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden aufgenommen.</item> <item quantity="one">Screenshot für den Fehlerbericht wird in <xliff:g id="NUMBER_0">%d</xliff:g> Sekunde aufgenommen.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Lautlos-Modus"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ton ist AUS."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ton ist AN."</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Bitte versuche es noch einmal."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Keine Fingerabdrücke erfasst."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dieses Gerät hat keinen Fingerabdrucksensor."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Der Sensor ist vorübergehend deaktiviert."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Gesichtsprüfung nicht möglich. Noch mal versuchen."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Face Unlock ist nicht eingerichtet."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock wird auf diesem Gerät nicht unterstützt."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Der Sensor ist vorübergehend deaktiviert."</string> <string name="face_name_template" msgid="3877037340223318119">"Gesicht <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-Debugging aktiviert"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Zum Deaktivieren von USB-Debugging tippen"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB-Debugging deaktivieren: auswählen"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Kabelloses Debugging verbunden"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tippen, um kabelloses Debugging zu deaktivieren"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Auswählen, um kabelloses Debugging zu deaktivieren."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test-Harnischmodus aktiviert"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Setz das Gerät auf die Werkseinstellungen zurück, um den Test-Harnischmodus zu deaktivieren."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serielle Konsole aktiviert"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Der Dienst im Vordergrund von <xliff:g id="PACKAGENAME">%1$s</xliff:g>, der im Hintergrund gestartet wurde, hat in zukünftigen R-Builds keine Zugriffsberechtigung mehr während der Nutzung. Siehe dazu go/r-bg-fgs-restriction und reiche einen Fehlerbericht ein."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Verknüpfung für Bedienungshilfen verwenden?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Verknüpfungen bearbeiten"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Abbrechen"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Verknüpfung deaktivieren"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Unkategorisiert"</string> <string name="importance_from_user" msgid="2782756722448800447">"Du hast die Wichtigkeit dieser Benachrichtigungen festgelegt."</string> <string name="importance_from_person" msgid="4235804979664465383">"Diese Benachrichtigung ist aufgrund der beteiligten Personen wichtig."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Es gibt bereits einen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g>. Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit diesem Konto erstellt?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt?"</string> <string name="language_selection_title" msgid="52674936078683285">"Sprache hinzufügen"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Geschäftlich"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Teilen mit geschäftlichen Apps nicht möglich"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Teilen mit privaten Apps nicht möglich"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Dein IT-Administrator lässt das Teilen zwischen privaten und geschäftlichen Apps nicht zu"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Geschäftliche Apps aktivieren"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Für Zugriff auf geschäftliche Apps und Kontakte geschäftliche Apps aktivieren"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Keine Apps verfügbar"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Keine Apps gefunden"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Arbeitsprofil aktivieren"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Audio bei Telefonanrufen aufnehmen oder wiedergeben"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Ermöglicht dieser App das Aufnehmen und Wiedergeben von Audio bei Telefonanrufen, wenn sie als Standard-Telefon-App festgelegt wurde."</string> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index e5cb63526675..c915bba83f3d 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Ο οργανισμός σας διαχειρίζεται αυτήν τη συσκευή και ενδέχεται να παρακολουθεί την επισκεψιμότητα δικτύου. Πατήστε για λεπτομέρειες."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Οι ρυθμίσεις τοποθεσίας άλλαξαν από τον διαχειριστή"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Πατήστε, για να δείτε τις ρυθμίσεις τοποθεσίας."</string> + <string name="country_detector" msgid="7023275114706088854">"Ανιχνευτής χώρας"</string> + <string name="location_service" msgid="2439187616018455546">"Υπηρεσία τοποθεσίας"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Υπηρεσία ειδοποίησης αισθητήρα"</string> + <string name="twilight_service" msgid="8964898045693187224">"Υπηρεσία Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Δεν είναι δυνατή η χρήση της εφαρμογής διαχειριστή. Η συσκευή σας θα διαγραφεί.\n\nΕάν έχετε ερωτήσεις, επικοινωνήστε με τον διαχειριστή του οργανισμού σας."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Η εκτύπωση απενεργοποιήθηκε από τον χρήστη <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,8 @@ <item quantity="other">Λήψη στιγμιότυπου οθόνης για αναφορά σφαλμάτων σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα.</item> <item quantity="one">Λήψη στιγμιότυπου οθόνης για αναφορά σφαλμάτων σε <xliff:g id="NUMBER_0">%d</xliff:g> δευτερόλεπτο.</item> </plurals> + <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Έγινε λήψη στιγμιότυπου οθόνης με αναφορά σφάλματος"</string> + <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Αποτυχία λήψης στιγμιότυπου οθόνης με αναφορά σφάλματος"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Λειτουργία σίγασης"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ο ήχος είναι απενεργοποιημένος"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ο ήχος είναι ενεργοποιημένος"</string> @@ -546,8 +552,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Δοκιμάστε ξανά."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Δεν έχουν καταχωριστεί δακτυλικά αποτυπώματα."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Δάχτυλο <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +596,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Αδύνατη επαλήθευση του προσώπου. Επανάληψη."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Δεν έχετε ρυθμίσει το Face Unlock."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Το Face Unlock δεν υποστηρίζεται σε αυτήν τη συσκευή."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string> <string name="face_name_template" msgid="3877037340223318119">"Πρόσωπο <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1322,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Απενεργοποιήστε τον εντοπισμό/διόρθ. σφαλμάτων USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο εντοπισμός σφαλμάτων μέσω ασύρματης σύνδεσης"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον εντοπισμό σφαλμάτων μέσω ασύρματης σύνδεσης"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Επιλέξτε, για να απενεργοποιήσετε τον εντοπισμό σφαλμάτων μέσω ασύρματης σύνδεσης."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Η λειτουργία περιβάλλοντος δοκιμών ενεργοποιήθηκε"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Εκτελέστε επαναφορά εργοστασιακών ρυθμίσεων για να απενεργοποιήσετε τη λειτουργία περιβάλλοντος δοκιμών."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Η σειριακή κονσόλα ενεργοποιήθηκε"</string> @@ -1621,8 +1628,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Η υπηρεσία στο προσκήνιο που ξεκίνησε από το παρασκήνιο από το πακέτο <xliff:g id="PACKAGENAME">%1$s</xliff:g> δεν θα έχει άδεια πρόσβασης μόνο κατά τη χρήση σε μελλοντικές εκδόσεις R. Ανατρέξτε στο go/r-bg-fgs-restriction και υποβάλετε αναφορά σφάλματος."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Αυξάνετε την ένταση ήχου πάνω από το επίπεδο ασφαλείας;\n\nΑν ακούτε μουσική σε υψηλή ένταση για μεγάλο χρονικό διάστημα ενδέχεται να προκληθεί βλάβη στην ακοή σας."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Να χρησιμοποιείται η συντόμευση προσβασιμότητας;"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Επεξεργασία συντομεύσεων"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Άκυρο"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Απενεργοποίηση συντόμευσης"</string> @@ -1845,6 +1851,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Μη κατηγοριοποιημένο"</string> <string name="importance_from_user" msgid="2782756722448800447">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string> <string name="importance_from_person" msgid="4235804979664465383">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g> (υπάρχει ήδη χρήστης με αυτόν τον λογαριασμό);"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string> <string name="language_selection_title" msgid="52674936078683285">"Προσθήκη γλώσσας"</string> @@ -2018,20 +2026,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικό"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Εργασία"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Δεν είναι δυνατή η κοινοποίηση σε εφαρμογές εργασιών"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Δεν είναι δυνατή η κοινοποίηση σε προσωπικές εφαρμογές"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ο διαχειριστής IT απέκλεισε την κοινοποίηση μεταξύ των προσωπικών εφαρμογών και των εφαρμογών εργασιών σας"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ενεργοποίηση εφαρμογών εργασιών"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ενεργοποίηση εφαρμογών εργασιών για πρόσβαση στις εφαρμογές εργασιών και τις επαφές"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Δεν υπάρχουν διαθέσιμες εφαρμογές"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Δεν ήταν δυνατή η εύρεση εφαρμογών"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Διακόπτης ενεργοποίησης προφίλ εργασίας"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Εγγραφή ή αναπαραγωγή ήχου σε τηλεφωνικές κλήσεις"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Επιτρέπει σε αυτήν την εφαρμογή, όταν ορίζεται ως προεπιλεγμένη εφαρμογή κλήσης, να εγγράφει ή να αναπαράγει ήχο σε τηλεφωνικές κλήσεις."</string> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 7ee98467017d..c5259fdaebf0 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Location settings changed by your admin"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tap to see your location settings."</string> + <string name="country_detector" msgid="7023275114706088854">"Country Detector"</string> + <string name="location_service" msgid="2439187616018455546">"Location Service"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,8 @@ <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item> <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item> </plurals> + <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot taken with bug report"</string> + <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Failed to take screenshot with bug report"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Silent mode"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sound is OFF"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sound is ON"</string> @@ -1316,6 +1322,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB debugging connected"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tap to turn off USB debugging"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Select to disable USB debugging."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wireless debugging connected"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tap to turn off wireless debugging"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Select to disable wireless debugging."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Harness Mode enabled"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Perform a factory reset to disable Test Harness Mode."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serial console enabled"</string> @@ -1842,6 +1851,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string> <string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string> <string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string> @@ -2023,4 +2034,6 @@ <string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string> <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string> <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 4ff597577be6..78db7589a22e 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Location settings changed by your admin"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tap to see your location settings."</string> + <string name="country_detector" msgid="7023275114706088854">"Country Detector"</string> + <string name="location_service" msgid="2439187616018455546">"Location Service"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,8 @@ <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item> <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item> </plurals> + <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot taken with bug report"</string> + <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Failed to take screenshot with bug report"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Silent mode"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sound is OFF"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sound is ON"</string> @@ -1316,6 +1322,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB debugging connected"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tap to turn off USB debugging"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Select to disable USB debugging."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wireless debugging connected"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tap to turn off wireless debugging"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Select to disable wireless debugging."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Harness Mode enabled"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Perform a factory reset to disable Test Harness Mode."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serial console enabled"</string> @@ -1842,6 +1851,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string> <string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string> <string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string> @@ -2023,4 +2034,6 @@ <string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string> <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string> <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 7ee98467017d..c5259fdaebf0 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Location settings changed by your admin"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tap to see your location settings."</string> + <string name="country_detector" msgid="7023275114706088854">"Country Detector"</string> + <string name="location_service" msgid="2439187616018455546">"Location Service"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,8 @@ <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item> <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item> </plurals> + <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot taken with bug report"</string> + <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Failed to take screenshot with bug report"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Silent mode"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sound is OFF"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sound is ON"</string> @@ -1316,6 +1322,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB debugging connected"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tap to turn off USB debugging"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Select to disable USB debugging."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wireless debugging connected"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tap to turn off wireless debugging"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Select to disable wireless debugging."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Harness Mode enabled"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Perform a factory reset to disable Test Harness Mode."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serial console enabled"</string> @@ -1842,6 +1851,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string> <string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string> <string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string> @@ -2023,4 +2034,6 @@ <string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string> <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string> <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 7ee98467017d..c5259fdaebf0 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Location settings changed by your admin"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tap to see your location settings."</string> + <string name="country_detector" msgid="7023275114706088854">"Country Detector"</string> + <string name="location_service" msgid="2439187616018455546">"Location Service"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,8 @@ <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item> <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item> </plurals> + <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot taken with bug report"</string> + <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Failed to take screenshot with bug report"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Silent mode"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sound is OFF"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sound is ON"</string> @@ -1316,6 +1322,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB debugging connected"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tap to turn off USB debugging"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Select to disable USB debugging."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wireless debugging connected"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tap to turn off wireless debugging"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Select to disable wireless debugging."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Harness Mode enabled"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Perform a factory reset to disable Test Harness Mode."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serial console enabled"</string> @@ -1842,6 +1851,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorised"</string> <string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string> <string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string> @@ -2023,4 +2034,6 @@ <string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string> <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string> <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as a default dialler application, to record or play audio in telephony calls."</string> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index bef34420cc5f..eb546534f94c 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Your organization manages this device and may monitor network traffic. Tap for details."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Location settings changed by your admin"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tap to see your location settings."</string> + <string name="country_detector" msgid="7023275114706088854">"Country Detector"</string> + <string name="location_service" msgid="2439187616018455546">"Location Service"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string> <string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organization\'s admin."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,8 @@ <item quantity="other">Taking screenshot for bug report in <xliff:g id="NUMBER_1">%d</xliff:g> seconds.</item> <item quantity="one">Taking screenshot for bug report in <xliff:g id="NUMBER_0">%d</xliff:g> second.</item> </plurals> + <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot taken with bug report"</string> + <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Failed to take screenshot with bug report"</string> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Silent mode"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sound is OFF"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sound is ON"</string> @@ -1316,6 +1322,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB debugging connected"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tap to turn off USB debugging"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Select to disable USB debugging."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wireless debugging connected"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tap to turn off wireless debugging"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Select to disable wireless debugging."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Harness Mode enabled"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Perform a factory reset to disable Test Harness Mode."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serial console enabled"</string> @@ -1842,6 +1851,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Uncategorized"</string> <string name="importance_from_user" msgid="2782756722448800447">"You set the importance of these notifications."</string> <string name="importance_from_person" msgid="4235804979664465383">"This is important because of the people involved."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Add a language"</string> @@ -2023,4 +2034,6 @@ <string name="resolver_no_apps_available" msgid="7710339903040989654">"No apps available"</string> <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We couldn’t find any apps"</string> <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Record or play audio in telephony calls"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Allows this app, when assigned as default dialer application, to record or play audio in telephony calls."</string> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 29318bd48081..7933f68c2e48 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -191,8 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"El administrador no permite hacer un uso personal del dispositivo"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Dispositivo administrado"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y es posible que controle el tráfico de red. Presiona para obtener más información."</string> - <string name="location_changed_notification_title" msgid="4119726617105166830">"Tu administrador cambió la configuración de la ubicación"</string> + <string name="location_changed_notification_title" msgid="4119726617105166830">"El administrador cambió la configuración de la ubicación"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Presiona para ver la configuración de la ubicación."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector de país"</string> + <string name="location_service" msgid="2439187616018455546">"Servicio de ubicación"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Servicio de notificaciones del sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Servicio de Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede usar la app de administrador. Ahora se borrará tu dispositivo.\n\nSi tienes preguntas, comunícate con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> inhabilitó la impresión."</string> @@ -245,6 +249,10 @@ <item quantity="other">Se tomará una captura de pantalla para el informe de errores en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> <item quantity="one">Se tomará una captura de pantalla para el informe de errores en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"El sonido está Desactivado"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"El sonido está Activado"</string> @@ -431,7 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"Esta privilegiada | app del sistema puede tomar fotos y grabar videos con una cámara del sistema en cualquier momento. También se requiere que la app posea el permiso android.permission.CAMERA."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"controlar la vibración"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Permite que la aplicación controle la vibración."</string> - <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que la app acceda al estado del vibrador."</string> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que la app acceda al estado del modo de vibración."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"llamar directamente a números de teléfono"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Permite que la aplicación haga llamadas a números de teléfono sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"acceder al servicio IMS para realizar llamadas"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Vuelve a intentarlo."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se registraron huellas digitales."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"No se pudo verificar la cara. Vuelve a intentarlo."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"No configuraste el Desbloqueo facial."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"No se admite el Desbloqueo facial en este dispositivo."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Se inhabilitó temporalmente el sensor."</string> <string name="face_name_template" msgid="3877037340223318119">"Rostro <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Presiona para desactivar la depuración por USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para desactivar la depuración por USB"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Se conectó la depuración inalámbrica"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Presiona para desactivar la depuración inalámbrica"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecciona para inhabilitar la depuración inalámbrica."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Se habilitó el modo de agente de prueba"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Restablece la configuración de fábrica para inhabilitar el modo de agente de prueba."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Se habilitó la consola en serie"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servicio que pasó del segundo al primer plano de <xliff:g id="PACKAGENAME">%1$s</xliff:g> no tendrá permiso durante el uso en las próximas compilaciones de R. Ve a go/r-bg-fgs-restriction y envía un informe de errores."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar a un alto volumen durante largos períodos puede dañar tu audición."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Usar acceso directo de accesibilidad?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cuando la combinación de teclas está activada, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar acceso directo"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sin categoría"</string> <string name="importance_from_user" msgid="2782756722448800447">"Estableciste la importancia de estas notificaciones."</string> <string name="importance_from_person" msgid="4235804979664465383">"Es importante debido a las personas involucradas."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ya existe un usuario con esta cuenta)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"¿Deseas permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Agregar un idioma"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el depósito RESTRICTED"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"No se puede compartir con apps de trabajo"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"No se puede compartir con apps personales"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Tu administrador de TI bloqueó el uso compartido entre las apps personales y de trabajo"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa las apps de trabajo"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa las apps de trabajo para acceder a apps y contactos de trabajo"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"No hay apps disponibles"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"No se pudo encontrar ninguna app"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activar perfil de trabajo"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Graba o reproduce audio en llamadas de telefonía"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que esta app grabe o reproduzca audio en llamadas de telefonía cuando se la asigna como aplicación de teléfono predeterminada."</string> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 5db4f42a9a22..7bbfcae2fe2e 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -191,8 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"El administrador no permite hacer un uso personal del dispositivo"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"El dispositivo está administrado"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y puede supervisar el tráfico de red. Toca la notificación para obtener más información."</string> - <string name="location_changed_notification_title" msgid="4119726617105166830">"Tu administrador ha cambiado los ajustes de ubicación-"</string> + <string name="location_changed_notification_title" msgid="4119726617105166830">"Tu administrador ha cambiado los ajustes de ubicación"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Toca para ver tus ajustes de ubicación."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector de país"</string> + <string name="location_service" msgid="2439187616018455546">"Servicio de ubicación"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Servicio de notificación de sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Servicio de Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string> <string name="factory_reset_message" msgid="2657049595153992213">"No se puede utilizar la aplicación de administración. Se borrarán todos los datos del dispositivo.\n\nSi tienes alguna pregunta, ponte en contacto con el administrador de tu organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha inhabilitado la impresión."</string> @@ -245,6 +249,10 @@ <item quantity="other">La captura de pantalla para el informe de errores se realizará en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> <item quantity="one">La captura de pantalla para el informe de errores se realizará en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencio"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"El sonido está desactivado. Activar"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"El sonido está activado. Desactivar"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Vuelve a intentarlo."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se ha registrado ninguna huella digital."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor está inhabilitado en estos momentos."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"No se ha verificado tu cara. Vuelve a intentarlo."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"No has configurado el desbloqueo facial."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"El desbloqueo facial no está disponible en este dispositivo."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor está inhabilitado en estos momentos."</string> <string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1227,9 +1233,9 @@ <string name="volume_music" msgid="7727274216734955095">"Volumen de multimedia"</string> <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Reproduciendo a través de Bluetooth"</string> <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Tono de silencio establecido"</string> - <string name="volume_call" msgid="7625321655265747433">"Volumen de la llamada"</string> - <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volumen de la llamada de Bluetooth"</string> - <string name="volume_alarm" msgid="4486241060751798448">"Volumen de la alarma"</string> + <string name="volume_call" msgid="7625321655265747433">"Volumen de llamada"</string> + <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volumen de llamada Bluetooth"</string> + <string name="volume_alarm" msgid="4486241060751798448">"Volumen de alarma"</string> <string name="volume_notification" msgid="6864412249031660057">"Volumen de notificaciones"</string> <string name="volume_unknown" msgid="4041914008166576293">"Volumen"</string> <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Volumen de Bluetooth"</string> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración USB habilitada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tocar para desactivar depuración USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración USB"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecciona para inhabilitar la depuración inalámbrica."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo de agente de prueba habilitado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Restablece los ajustes de fábrica para inhabilitar el modo de agente de prueba."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Se ha habilitado la consola en serie"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servicio en primer plano que se inició en segundo plano en <xliff:g id="PACKAGENAME">%1$s</xliff:g> no tendrá permisos en compilaciones R futuras mientras se estén usando. Ve a go/r-bg-fgs-restriction y envía un informe de errores."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si el acceso directo está activado, pulsa los dos botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar accesos directos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar acceso directo"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sin clasificar"</string> <string name="importance_from_user" msgid="2782756722448800447">"Tú determinas la importancia de estas notificaciones."</string> <string name="importance_from_person" msgid="4235804979664465383">"Esto es importante por los usuarios implicados."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>, que ya tiene uno?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Añadir un idioma"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"No se puede compartir con las aplicaciones de trabajo"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"No se puede compartir con las aplicaciones personales"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"No se puede compartir contenido entre las aplicaciones personales y las de trabajo porque el administrador de TI ha bloqueado esta función"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa las aplicaciones de trabajo"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa las aplicaciones de trabajo para acceder a ellas y a los contactos"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"No hay ninguna aplicación disponible"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"No se ha podido encontrar ninguna aplicación"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Switch on work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Grabar o reproducir audio en llamadas telefónicas"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que la aplicación grabe o reproduzca audio en las llamadas telefónicas si está asignada como aplicación Teléfono predeterminada."</string> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 2c987161e468..34f3a6a51e22 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Teie organisatsioon haldab seda seadet ja võib jälgida võrguliiklust. Puudutage üksikasjade vaatamiseks."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Administraator muutis teie asukohaseadeid"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Puudutage oma asukohaseadete nägemiseks."</string> + <string name="country_detector" msgid="7023275114706088854">"Riigi tuvastaja"</string> + <string name="location_service" msgid="2439187616018455546">"Asukohateenus"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Anduri märguande teenus"</string> + <string name="twilight_service" msgid="8964898045693187224">"Teenus Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administraatori rakendust ei saa kasutada. Teie seade tühjendatakse nüüd.\n\nKui teil on küsimusi, võtke ühendust organisatsiooni administraatoriga."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Rakendus <xliff:g id="OWNER_APP">%s</xliff:g> on printimise keelanud."</string> @@ -245,6 +249,10 @@ <item quantity="other">Veaaruande jaoks ekraanipildi jäädvustamine <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast.</item> <item quantity="one">Veaaruande jaoks ekraanipildi jäädvustamine <xliff:g id="NUMBER_0">%d</xliff:g> sekundi pärast.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Hääletu režiim"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Heli on VÄLJAS"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Heli on SEES"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Proovige uuesti."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrm <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nägu ei saa kinnitada. Proovige uuesti."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Face Unlocki ei ole seadistatud."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Seade ei toeta Face Unlocki."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Andur on ajutiselt keelatud."</string> <string name="face_name_template" msgid="3877037340223318119">"Nägu <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-silumine ühendatud"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Puudutage USB silumise väljalülitamiseks"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Valige USB silumise keelamiseks"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Juhtmevaba silumine on ühendatud"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Puudutage juhtmevaba silumise väljalülitamiseks"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Valige juhtmevaba silumise keelamiseks."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Testrakendirežiim on lubatud"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Testrakendirežiimi keelamiseks taastage tehaseseaded."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Seeriakonsool on lubatud"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Taustal käitatud esiplaanil oleval teenusel paketist <xliff:g id="PACKAGENAME">%1$s</xliff:g> ei ole tulevastes R-järkudes luba „kui kasutuses”. Vaadake saiti go/r-bg-fgs-restriction ja esitage veaaruanne."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Kas suurendada helitugevuse taset üle soovitatud taseme?\n\nPikaajaline valju helitugevusega kuulamine võib kuulmist kahjustada."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Kas kasutada juurdepääsetavuse otseteed?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muuda otseteid"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Tühista"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Lülita otsetee välja"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Kategoriseerimata"</string> <string name="importance_from_user" msgid="2782756722448800447">"Teie määrasite nende märguannete tähtsuse."</string> <string name="importance_from_person" msgid="4235804979664465383">"See on tähtis osalevate inimeste tõttu."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g> (selle kontoga kasutaja on juba olemas)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Keele lisamine"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Isiklik"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Töö"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Töörakendustega ei saa jagada"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Isiklike rakendustega ei saa jagada"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Teie IT-administraator blokeeris isiklike ja töörakenduste vahel jagamise"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Lülita sisse töörakendused"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Lülitage sisse töörakendused, et töörakendustele ja -kontaktidele juurde pääseda"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Ühtegi rakendust pole saadaval"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Me ei leidnud ühtegi rakendust"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Lülita sisse tööprofiil"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefonikõnede heli salvestamine ja esitamine"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Kui see rakendus on määratud helistamise vaikerakenduseks, lubatakse sellel salvestada ja esitada telefonikõnede heli."</string> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 8e247fcc66b8..34cb6fbe8d3d 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -89,7 +89,7 @@ <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Ezin duzu egin larrialdi-deirik Wi-Fi bidez"</string> <string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertak"</string> <string name="notification_channel_call_forward" msgid="8230490317314272406">"Dei-desbideratzea"</string> - <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Larrialdi-deiak soilik jasotzeko modua"</string> + <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Larrialdi-zerbitzuen deiak jasotzeko modua"</string> <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Datu-konexioaren egoera"</string> <string name="notification_channel_sms" msgid="1243384981025535724">"SMS mezuak"</string> <string name="notification_channel_voice_mail" msgid="8457433203106654172">"Erantzungailuko mezuak"</string> @@ -191,10 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"Erabilera pertsonalerako utzi du gailua administratzaileak"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Jabeak kudeatzen du gailua"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Erakundeak kudeatzen du gailua eta baliteke sareko trafikoa gainbegiratzea. Sakatu hau xehetasunak ikusteko."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"Administratzaileak kokapen-ezarpenak aldatu ditu"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"Sakatu kokapen-ezarpenak ikusteko."</string> + <string name="country_detector" msgid="7023275114706088854">"Herrialde-hautemailea"</string> + <string name="location_service" msgid="2439187616018455546">"Kokapen-zerbitzua"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sentsorearen jakinarazpen-zerbitzua"</string> + <string name="twilight_service" msgid="8964898045693187224">"Ilunabarreko zerbitzua"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ezin da erabili administratzeko aplikazioa. Ezabatu egingo da gailuko eduki guztia.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string> @@ -247,6 +249,10 @@ <item quantity="other">Akatsen txostenaren argazkia aterako da <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru.</item> <item quantity="one">Akatsen txostenaren argazkia aterako da <xliff:g id="NUMBER_0">%d</xliff:g> segundo barru.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Isilik modua"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Soinua DESAKTIBATUTA dago"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Soinua AKTIBATUTA dago"</string> @@ -433,8 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"Pribilegioa duen sistema-aplikazio honek edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko. Halaber, android.permission.CAMERA baimena izan behar du aplikazioak."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"kontrolatu dardara"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Bibragailua kontrolatzeko aukera ematen die aplikazioei."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Dardara-egoera atzitzeko baimena ematen dio aplikazioari."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"deitu zuzenean telefono-zenbakietara"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"atzitu IMS dei-zerbitzua"</string> @@ -497,7 +502,7 @@ <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Tableta WiMAX sareetara konektatzeko edo haietatik deskonektatzeko baimena ematen die aplikazioei."</string> <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Android TV gailua WiMAX sareetara konektatzeko edo haietatik deskonektatzeko baimena ematen die aplikazioei."</string> <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Telefonoa WiMAX sareetara konektatzeko edo haietatik deskonektatzeko baimena ematen die aplikazioei."</string> - <string name="permlab_bluetooth" msgid="586333280736937209">"partekatu Bluetooth gailuekin"</string> + <string name="permlab_bluetooth" msgid="586333280736937209">"partekatu Bluetooth bidezko gailuekin"</string> <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Tabletaren Bluetooth konfigurazioa ikusteko eta parekatutako gailuekin konexioak egiteko eta onartzeko baimena ematen die aplikazioei."</string> <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Android TV gailuaren Bluetooth konexioaren konfigurazioa ikusteko eta parekatutako gailuekin konexioak sortzeko eta onartzeko baimena ematen die aplikazioei."</string> <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Telefonoaren Bluetooth konfigurazioa ikusteko eta parekatutako gailuekin konexioak egiteko eta onartzeko baimena ematen die aplikazioei."</string> @@ -549,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Saiatu berriro."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ez da erregistratu hatz-markarik."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sentsorea aldi baterako desgaitu da."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> hatza"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ezin da egiaztatu aurpegia. Saiatu berriro."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ez duzu konfiguratu aurpegiaren bidez desblokeatzeko aukera."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gailu honek ez du onartzen aurpegiaren bidez desblokeatzea."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string> <string-array name="face_error_vendor"> </string-array> @@ -1321,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB bidezko arazketa konektatuta"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Sakatu USB bidezko arazketa desaktibatzeko"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Hautatu USB bidezko arazketa desgaitzeko."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Konektatu da hari gabeko arazketa"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Sakatu hau hari gabeko arazketa desaktibatzeko"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Hautatu hau hari gabeko arazketa desgaitzeko"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Proba-materialeko modua gaitu da"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Proba-materialaren modua desgaitzeko, berrezarri jatorrizko datuak."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serie-kontsola gaituta dago"</string> @@ -1557,7 +1563,7 @@ <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Telefonoa"</string> <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Konektatu bozgorailuak oinarrira"</string> <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string> - <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Aurikularrak"</string> + <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"Entzungailuak"</string> <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string> <string name="default_audio_route_category_name" msgid="5241740395748134483">"Sistema"</string> <string name="bluetooth_a2dp_audio_route_name" msgid="4214648773120426288">"Bluetooth bidezko audioa"</string> @@ -1624,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> webgunearen atzeko planoak hasitako aurreko planoko zerbitzuak ez du izango erabili bitarteko baimenik etorkizuneko R konpilazioetan. Joan go/r-bg-fgs-restriction atalera eta egin akatsaren txostena."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erabilerraztasun-lasterbidea erabili nahi duzu?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editatu lasterbideak"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Utzi"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desaktibatu lasterbidea"</string> @@ -1848,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Kategoriarik gabea"</string> <string name="importance_from_user" msgid="2782756722448800447">"Zuk ezarri duzu jakinarazpen hauen garrantzia."</string> <string name="importance_from_person" msgid="4235804979664465383">"Garrantzitsua da eragiten dien pertsonengatik."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari? (Badago kontu hori duen erabiltzaile bat)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu <xliff:g id="APP">%1$s</xliff:g> aplikazioari?"</string> <string name="language_selection_title" msgid="52674936078683285">"Gehitu hizkuntza"</string> @@ -2021,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pertsonala"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Lanekoa"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ezin da partekatu laneko aplikazioekin"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ezin da partekatu aplikazio pertsonalekin"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IKT administratzaileak blokeatu egin du edukia aplikazio pertsonalen eta laneko aplikazioen artean partekatzeko aukera"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktibatu laneko aplikazioak"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktibatu laneko aplikazioak, haiek eta kontaktuak atzitzeko"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Ez dago aplikaziorik erabilgarri"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Ezin izan dugu aurkitu aplikaziorik"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktibatu laneko profila"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Grabatu edo erreproduzitu telefono-deietako audioa"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Aplikazio hau markagailu lehenetsia denean, telefono-deietako audioa grabatu edo erreproduzitzeko aukera ematen dio."</string> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index c603da3c1ee4..472bd0f1a64f 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"سازمانتان این دستگاه را مدیریت میکند و ممکن است ترافیک شبکه را پایش کند. برای اطلاع از جزئیات، ضربه بزنید."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"سرپرست شما تنظیمات مکان را تغییر داده است"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"برای مشاهده تنظیمات مکان ضربه بزنید."</string> + <string name="country_detector" msgid="7023275114706088854">"کشوریاب"</string> + <string name="location_service" msgid="2439187616018455546">"خدمات مکان"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"سرویس اعلان حسگر"</string> + <string name="twilight_service" msgid="8964898045693187224">"سرویس Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string> <string name="factory_reset_message" msgid="2657049595153992213">"برنامه سرپرست سیستم را نمیتوان استفاده کرد. دستگاه شما در این لحظه پاک میشود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string> @@ -245,6 +249,10 @@ <item quantity="one">تا <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دیگر عکس صفحهنمایش برای گزارش اشکال گرفته میشود.</item> <item quantity="other">تا <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دیگر عکس صفحهنمایش برای گزارش اشکال گرفته میشود.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"حالت ساکت"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"صدا خاموش است"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"صدا روشن است"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"دوباره امتحان کنید."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"اثر انگشتی ثبت نشده است."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر بهطور موقت غیرفعال است."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"چهره تأیید نشد. دوباره امتحان کنید."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"«بازگشایی با چهره» را راهاندازی نکردهاید."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"«بازگشایی با چهره» در این دستگاه پشتیبانی نمیشود."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"حسگر بهطور موقت غیرفعال است."</string> <string name="face_name_template" msgid="3877037340223318119">"چهره <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"اشکالزدایی USB متصل شد"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"برای خاموش کردن اشکالزدایی USB ضربه بزنید"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"انتخاب کنید تا رفع عیب USB غیرفعال شود."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"اشکالزدایی بیسیم متصل است"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"برای خاموش کردن اشکالزدایی بیسیم ضربه بزنید"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"برای غیرفعال کردن اشکالزدایی بیسیم انتخاب کنید."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"«حالت مجموعه دادههای تست» فعال شد"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"برای غیرفعال کردن «حالت مجموعه دادههای تست»، بازنشانی کارخانهای کنید."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"کنسول سریال فعال است"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"سرویس پیشنمای <xliff:g id="PACKAGENAME">%1$s</xliff:g>، که در پسزمینه شروع شده، در ساختهای آتی R اجازهٔ حین استفاده نخواهد داشت. لطفاً به go/r-bg-fgs-restriction بروید و گزارش اشکال ارسال کنید."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"میزان صدا را به بالاتر از حد توصیه شده افزایش میدهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی میتواند به شنواییتان آسیب وارد کند."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"از میانبر دسترسپذیری استفاده شود؟"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"وقتی میانبر روشن باشد، با فشار دادن هردو دکمه صدا بهمدت ۳ ثانیه ویژگی دسترسپذیری فعال میشود."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ویرایش میانبرها"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"لغو"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"خاموش کردن میانبر"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"دستهبندینشده"</string> <string name="importance_from_user" msgid="2782756722448800447">"شما اهمیت این اعلانها را تنظیم میکنید."</string> <string name="importance_from_person" msgid="4235804979664465383">"به دلیل افراد درگیر مهم است."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"به<xliff:g id="APP">%1$s</xliff:g> اجازه میدهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> (کاربری با این حساب درحالحاضر وجود دارد) کاربری جدید ایجاد کند؟"</string> <string name="user_creation_adding" msgid="7305185499667958364">"به <xliff:g id="APP">%1$s</xliff:g> اجازه میدهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> کاربری جدید ایجاد کند؟"</string> <string name="language_selection_title" msgid="52674936078683285">"افزودن زبان"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصی"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"کاری"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"همرسانی بااستفاده از «برنامههای کاری» امکانپذیر نیست"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"همرسانی بااستفاده از برنامههای شخصی امکانپذیر نیست"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"سرپرست فناوری اطلاعات شما همرسانی بین برنامههای شخصی و کاری را مسدود کرده است"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"روشن کردن «برنامههای کاری»"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"برای دسترسی به برنامههای کاری و مخاطبین، «برنامههای کاری» را روشن کنید"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"هیچ برنامهای در دسترس نیست"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"هیچ برنامهای پیدا نکردیم"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"فعال کردن نمایه کاری"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ضبط یا پخش صدا در تماسهای تلفنی"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"به این برنامه اجازه میدهد وقتی بهعنوان برنامه شمارهگیر پیشفرض تنظیم شده است، در تماسهای تلفنی صدا ضبط یا پخش کند."</string> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 5ee67d95a418..6aa1a9bccbd5 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisaatiosi hallinnoi tätä laitetta ja voi tarkkailla verkkoliikennettä. Katso lisätietoja napauttamalla."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Järjestelmänvalvoja muutti sijaintiasetuksia"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Katso sijaintiasetukset napauttamalla."</string> + <string name="country_detector" msgid="7023275114706088854">"Maan tunnistin"</string> + <string name="location_service" msgid="2439187616018455546">"Sijaintipalvelu"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Anturin ilmoituspalvelu"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight-palvelu"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hallintasovellusta ei voi käyttää. Laitteen tiedot pyyhitään.\n\nPyydä ohjeita järjestelmänvalvojaltasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> on poistanut tulostuksen käytöstä."</string> @@ -245,6 +249,10 @@ <item quantity="other">Virheraporttiin otetaan kuvakaappaus <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua.</item> <item quantity="one">Virheraporttiin otetaan kuvakaappaus <xliff:g id="NUMBER_0">%d</xliff:g> sekunnin kuluttua.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Äänetön tila"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Äänet ovat POISSA KÄYTÖSTÄ"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Äänet ovat KÄYTÖSSÄ"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Yritä uudelleen."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Sormenjälkiä ei ole otettu käyttöön."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tunnistin poistettu väliaikaisesti käytöstä."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Kasvoja ei voi vahvistaa. Yritä uudelleen."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Et ole määrittänyt Face Unlockia."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Tämä laite ei tue Face Unlockia."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Tunnistin poistettu väliaikaisesti käytöstä."</string> <string name="face_name_template" msgid="3877037340223318119">"Kasvot <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-vianetsintä yhdistetty"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Poista USB-virheenkorjaus käytöstä napauttamalla."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Langaton virheenkorjaus yhdistetty"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Poista langaton virheenkorjaus käytöstä napauttamalla"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Poista langaton virheenkorjaus käytöstä valitsemalla tämä."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Testikehystila käytössä"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Palauta tehdasasetukset, niin voit poistaa testikehystilan käytöstä."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Sarjakonsoli käytössä"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Taustalla aloitettu etualan palvelu (<xliff:g id="PACKAGENAME">%1$s</xliff:g>) ei ole käytön aikana sallittu R:n tulevissa versioissa. Lue go/r-bg-fgs-restriction ja lähetä virheraportti."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Nostetaanko äänenvoimakkuus suositellun tason yläpuolelle?\n\nPitkäkestoinen kova äänenvoimakkuus saattaa heikentää kuuloa."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Käytetäänkö esteettömyyden pikanäppäintä?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Muokkaa pikakuvakkeita"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Peruuta"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Poista pikanäppäin käytöstä"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Luokittelematon"</string> <string name="importance_from_user" msgid="2782756722448800447">"Voit valita näiden ilmoitusten tärkeyden."</string> <string name="importance_from_person" msgid="4235804979664465383">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>) – tällä käyttäjällä on jo tili?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>)?"</string> <string name="language_selection_title" msgid="52674936078683285">"Lisää kieli"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Henkilökohtainen"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Työ"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ei voi jakaa työsovellusten kanssa"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ei voi jakaa henkilökohtaisten sovellusten kanssa"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT-järjestelmänvalvojasi esti jakamisen henkilökohtaisten ja työsovellusten välillä"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ota työsovellukset käyttöön"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ota työsovellukset käyttöön päästäksesi työsovelluksiin ja yhteystietoihin"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Sovelluksia ei ole käytettävissä"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Sovelluksia ei löytynyt"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ota työprofiili käyttöön"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Äänen tallentaminen tai toistaminen puheluiden aikana"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Sallii tämän sovelluksen tallentaa tai toistaa ääntä puheluiden aikana, kun sovellus on valittu oletuspuhelusovellukseksi."</string> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 7c4dd03e13eb..6f47049851d9 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -191,10 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"L\'administrateur a libéré l\'appareil pour un usage personnel"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Touchez ici pour obtenir plus d\'information."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"Les paramètres de localisation ont été changés par votre administrateur"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"Touchez l\'écran pour voir vos paramètres de localisation."</string> + <string name="country_detector" msgid="7023275114706088854">"Détecteur de pays"</string> + <string name="location_service" msgid="2439187616018455546">"Service de localisation"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Service de notification de capteur"</string> + <string name="twilight_service" msgid="8964898045693187224">"Service de crépuscule"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -247,6 +249,10 @@ <item quantity="one">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> seconde.</item> <item quantity="other">Saisie d\'écran pour le rapport de bogue dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Le son est désactivé."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Le son est activé."</string> @@ -433,8 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"Cette application privilégiée | système peut prendre des photos ou filmer des vidéos à l\'aide d\'un appareil photo système en tout temps. L\'application doit également posséder l\'autorisation android.permission.CAMERA"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"gérer le vibreur"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Permet à l\'application de gérer le vibreur de l\'appareil."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permet à l\'application d\'accéder au mode vibration."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"appeler directement des numéros de téléphone"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Des applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"accéder au service d\'appel IMS"</string> @@ -549,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Réessayer."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Le capteur a été désactivé temporairement."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Impossible de vérifier le visage. Réessayez."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Vous n\'avez pas config. le déverr. par reconn. faciale."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Cet appar. ne prend pas en charge le déverr. par reconn. faciale."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Le capteur a été désactivé temporairement."</string> <string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1321,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Débogage USB activé"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Touchez l\'écran pour désactiver le débogage USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Sélectionnez cette option pour désactiver le débogage USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Débogage sans fil connecté"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Touchez l\'écran pour désactiver le débogage sans fil"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Sélectionnez cette option pour désactiver le débogage sans fil."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Mode Logiciel de test activé"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Effectuez une réinitialisation pour désactiver le mode Logiciel de test."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"La console série est activée"</string> @@ -1624,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Le service de premier plan qui a démarré en arrière-plan provenant de <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne disposera pas de l\'autorisation pendant l\'utilisation dans les futures versions R. Veuillez accéder à go/r-bg-fgs-restriction et envoyer un rapport de bogue."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au-dessus du niveau recommandé?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuler"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Désactiver le raccourci"</string> @@ -1848,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sans catégorie"</string> <string name="importance_from_user" msgid="2782756722448800447">"Vous définissez l\'importance de ces notifications."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ces notifications sont importantes en raison des participants."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un utilisateur <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur est déjà associé à ce compte)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string> @@ -2021,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Bureau"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Partage impossible avec les applications professionnelles"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Partage impossible avec les applications personnelles"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Votre administrateur informatique a bloqué le partage entre vos applications personnelles et professionnelles"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activer les applications professionnelles"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activez les applications professionnelles pour accéder à celles-ci ainsi qu\'à vos contacts professionnels"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Aucune application disponible"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nous n\'avons trouvé aucune application"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activer le profil professionnel"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Enregistrer ou lire du contenu audio lors des appels téléphoniques"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permet à cette application, lorsqu\'elle est définie comme composeur par défaut, d\'enregistrer ou de lire du contenu audio lors des appels téléphoniques."</string> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 9d2e267472e3..20f0406ebb7a 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Appuyez ici pour obtenir plus d\'informations."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Paramètres de localisation modifiés par l\'administrateur"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Appuyez pour afficher les paramètres de localisation."</string> + <string name="country_detector" msgid="7023275114706088854">"Détecteur de pays"</string> + <string name="location_service" msgid="2439187616018455546">"Service de localisation"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Service de notification du capteur"</string> + <string name="twilight_service" msgid="8964898045693187224">"Service Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="one">Capture d\'écran pour le rapport de bug dans <xliff:g id="NUMBER_1">%d</xliff:g> seconde</item> <item quantity="other">Capture d\'écran pour le rapport de bug dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode silencieux"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Le son est désactivé."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Le son est activé."</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Veuillez réessayer."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Capteur temporairement désactivé."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Impossible de valider votre visage. Réessayez."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Face Unlock n\'est pas configuré."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock n\'est pas compatible avec cet appareil."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Capteur temporairement désactivé."</string> <string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Débogage USB activé"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Appuyez pour désactiver le débogage USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Sélectionnez cette option pour désactiver le débogage USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Débogage via Wi-Fi activé"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Appuyez pour désactiver le débogage via Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Sélectionnez cette option pour désactiver le débogage via Wi-Fi."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Mode Atelier de test activé"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Rétablissez la configuration d\'usine pour désactiver le mode Atelier de test."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Console série activée"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Le service de premier plan qui a démarré en arrière-plan et provenant de <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne disposera pas de l\'autorisation \"pendant l\'utilisation\" dans les futurs builds R. Veuillez accéder à go/r-bg-fgs-restriction et envoyer un rapport de bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au dessus du niveau recommandé ?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité ?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour démarrer une fonctionnalité d\'accessibilité."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifier les raccourcis"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuler"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Désactiver le raccourci"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sans catégorie"</string> <string name="importance_from_user" msgid="2782756722448800447">"Vous définissez l\'importance de ces notifications."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ces notifications sont importantes en raison des participants."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> (un utilisateur associé à ce compte existe déjà) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Ajouter une langue"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Professionnel"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Partage impossible avec les applications professionnelles"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Partage impossible avec les applications personnelles"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Votre administrateur informatique a bloqué le partage entre vos applications personnelles et professionnelles"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activer les applications professionnelles"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activez les applications professionnelles pour accéder à celles-ci ainsi qu\'à vos contacts pour le travail"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Aucune application disponible"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Aucune application détectée"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activer le profil professionnel"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Enregistrer ou lire du contenu audio lors des appels téléphoniques"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permet à cette application d\'enregistrer ou de lire du contenu audio lors des appels téléphoniques lorsqu\'elle est définie comme clavier par défaut."</string> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 0170f1659b30..cee03a1ad806 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"A túa organización xestiona este dispositivo e pode controlar o tráfico de rede. Toca para obter máis detalles."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"O administrador cambiou a configuración de localización"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Toca para ver a configuración de localización."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector do país"</string> + <string name="location_service" msgid="2439187616018455546">"Servizo de localización"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Servizo de notificacións dos sensores"</string> + <string name="twilight_service" msgid="8964898045693187224">"Servizo Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string> @@ -245,6 +249,10 @@ <item quantity="other">Vaise facer unha captura de pantalla para o informe de erros en <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> <item quantity="one">Vaise facer unha captura de pantalla para o informe de erros en <xliff:g id="NUMBER_0">%d</xliff:g> segundo.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo de silencio"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"O son está desactivado"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O son está activado"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Téntao de novo."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Non se rexistraron impresións dixitais."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Desactivouse o sensor temporalmente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Non se puido verificar a cara. Téntao de novo."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Non configuraches o desbloqueo facial."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Este dispositivo non admite o desbloqueo facial."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Desactivouse o sensor temporalmente."</string> <string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración por USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca para desactivar a depuración por USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecciona a opción para desactivar a depuración por USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"A depuración sen fíos está conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar a depuración sen fíos"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecciona para desactivar a depuración sen fíos."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Activouse o modo de axente de proba"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Restablece a configuración de fábrica para desactivar o modo de axente de proba."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"A consola de serie está activada"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Nas futuras compilacións R, o servizo en primeiro plano iniciado en segundo plano desde <xliff:g id="PACKAGENAME">%1$s</xliff:g> non terá permiso mentres estea en uso. Consulta go/r-bg-fgs-restriction e presenta un informe de erros."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Queres subir o volume máis do nivel recomendado?\n\nA reprodución de son a un volume elevado durante moito tempo pode provocar danos nos oídos."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Queres utilizar o atallo de accesibilidade?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atallos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desactivar atallo"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sen clasificar"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ti defines a importancia destas notificacións."</string> <string name="importance_from_person" msgid="4235804979664465383">"É importante polas persoas involucradas."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Engadir un idioma"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Traballo"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Non se pode compartir información coas aplicacións do traballo"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Non se pode compartir información coas aplicacións persoais"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"O teu administrador de TI bloqueou a función de compartir información entre as aplicacións persoais e as do traballo"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activa as aplicacións do traballo"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activa as aplicacións do traballo para acceder a elas e aos contactos do traballo"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Non hai aplicacións dispoñibles"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Non se puideron atopar aplicacións"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Activar perfil do traballo"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou reproducir audio en chamadas telefónicas"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que esta aplicación, cando está asignada como aplicación predeterminada do marcador, grave e reproduza audio en chamadas telefónicas."</string> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 8b0b37448dec..c718124356d8 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -191,10 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"વ્યવસ્થાપકે ડિવાઇસ વ્યક્તિગત ઉપયોગ માટે આપી દીધું છે"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ઉપકરણ સંચાલિત છે"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"તમારી સંસ્થા આ ઉપકરણનું સંચાલન કરે છે અને નેટવર્ક ટ્રાફિફનું નિયમન કરી શકે છે. વિગતો માટે ટૅપ કરો."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"તમારા વ્યવસ્થાપક દ્વારા સ્થાન સેટિંગ બદલવામાં આવ્યાં"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"તમારા સ્થાન સેટિંગને જોવા માટે ટૅપ કરો."</string> + <string name="country_detector" msgid="7023275114706088854">"દેશને ઓળખાવનારી સુવિધા"</string> + <string name="location_service" msgid="2439187616018455546">"સ્થાન સેવા"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"સેન્સર નોટિફિકેશન સેવા"</string> + <string name="twilight_service" msgid="8964898045693187224">"ટ્વાઇલાઇટ સેવા"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string> <string name="factory_reset_message" msgid="2657049595153992213">"વ્યવસ્થાપક ઍપનો ઉપયોગ કરી શકાશે નહીં. તમારું ઉપકરણ હવે કાઢી નાખવામાં આવશે.\n\nજો તમને પ્રશ્નો હોય, તો તમારી સંસ્થાના વ્યવસ્થાપકનો સંપર્ક કરો."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> દ્વારા પ્રિન્ટ કરવાનું બંધ કરાયું છે."</string> @@ -247,6 +249,10 @@ <item quantity="one">બગ રિપોર્ટ માટે <xliff:g id="NUMBER_1">%d</xliff:g> સેકન્ડમાં સ્ક્રીનશોટ લઈ રહ્યાં છે.</item> <item quantity="other">બગ રિપોર્ટ માટે <xliff:g id="NUMBER_1">%d</xliff:g> સેકન્ડમાં સ્ક્રીનશોટ લઈ રહ્યાં છે.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"સાઇલેન્ટ મોડ"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"અવાજ બંધ છે"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ધ્વનિ ચાલુ છે"</string> @@ -433,8 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"આ વિશેષાધિકૃત | સિસ્ટમ ઍપ કોઈપણ સમયે સિસ્ટમ કૅમેરાનો ઉપયોગ કરીને ફોટા લઈ અને વીડિયો રેકોર્ડ કરી શકે છે. ઍપ દ્વારા આયોજિત કરવા માટે android.permission.CAMERAની પરવાનગી પણ જરૂરી છે"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"વાઇબ્રેશન નિયંત્રિત કરો"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"ઍપને વાઇબ્રેટર સ્થિતિને ઍક્સેસ કરવાની મંજૂરી આપે છે."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"સીધા જ ફોન નંબર્સ પર કૉલ કરો"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"એપ્લિકેશનને તમારા હસ્તક્ષેપ વિના ફોન નંબર્સ પર કૉલ કરવાની મંજૂરી આપે છે. આ અનપેક્ષિત શુલ્ક અથવા કૉલ્સમાં પરિણમી શકે છે. નોંધો કે આ એપ્લિકેશનને કટોકટીના નંબર્સ પર કૉલ કરવાની મંજૂરી આપતું નથી. દુર્ભાવનાપૂર્ણ ઍપ્લિકેશનો તમારી પુષ્ટિ વિના કૉલ્સ કરીને તમારા પૈસા ખર્ચ કરી શકે છે."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS કૉલ સેવા ઍક્સેસ કરો"</string> @@ -549,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ફરી પ્રયાસ કરો."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"કોઈ ફિંગરપ્રિન્ટની નોંધણી કરવામાં આવી નથી."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"આંગળી <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"ચહેરો ચકાસી શકાતો નથી. ફરી પ્રયાસ કરો."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"તમે ફેસ અનલૉકનું સેટઅપ કર્યું નથી."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"આ ડિવાઇસ પર ફેસ અનલૉક કરવાની સુવિધા નથી."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string> <string name="face_name_template" msgid="3877037340223318119">"ચહેરાનું <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1321,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ડીબગિંગ કનેક્ટ થયું."</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ડિબગીંગ બંધ કરવા માટે ટૅપ કરો"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ડિબગીંગને અક્ષમ કરવા માટે પસંદ કરો."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"વાયરલેસ ડિબગીંગ કનેક્ટ કરો"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"વાયરલેસ ડિબગીંગ બંધ કરવા માટે ટૅપ કરો"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"વાયરલેસ ડિબગીંગ બંધ કરવા માટે પસંદ કરો."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ટેસ્ટ હાર્નેસ મોડ ચાલુ કર્યો"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ટેસ્ટ હાર્નેસ મોડ બંધ કરવા માટે ફૅક્ટરી રીસેટ કરો."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"સિરીયલ કન્સોલ ચાલુ થયો"</string> @@ -1624,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"બૅકગ્રાઉન્ડમાં શરૂ થયેલી <xliff:g id="PACKAGENAME">%1$s</xliff:g>ની ફોરગ્રાઉન્ડ સેવા પાસે ભવિષ્યની R બિલ્ડમાં ઉપયોગમાં હોય તે સમયની પરવાનગી હશે નહીં. કૃપા કરીને go/r-bg-fgs-restriction જુઓ અને ભૂલનો અહેવાલ દાખલ કરો."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ભલામણ કરેલ સ્તરની ઉપર વૉલ્યૂમ વધાર્યો?\n\nલાંબા સમય સુધી ઊંચા અવાજે સાંભળવું તમારી શ્રવણક્ષમતાને નુકસાન પહોંચાડી શકે છે."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ઍક્સેસિબિલિટી શૉર્ટકટનો ઉપયોગ કરીએ?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"શૉર્ટકટમાં ફેરફાર કરો"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"રદ કરો"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"શૉર્ટકટ બંધ કરો"</string> @@ -1848,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"અવર્ગીકૃત"</string> <string name="importance_from_user" msgid="2782756722448800447">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string> <string name="importance_from_person" msgid="4235804979664465383">"શામેલ થયેલ લોકોને કારણે આ મહત્વપૂર્ણ છે."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ (આ એકાઉન્ટ માટે એક વપરાશકર્તા પહેલાંથી અસ્તિત્વમાં છે) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ ?"</string> <string name="language_selection_title" msgid="52674936078683285">"ભાષા ઉમેરો"</string> @@ -2021,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"વ્યક્તિગત"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"કાર્યાલય"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ઑફિસ માટેની ઍપની સાથે શેર કરી શકતાં નથી"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"વ્યક્તિગત ઍપની સાથે શેર કરી શકતાં નથી"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"તમારા IT વ્યવસ્થાપકે વ્યક્તિગત અને ઑફિસ માટેની ઍપ વચ્ચે શેરિંગની સુવિધાને બ્લૉક કરી છે"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ઑફિસ માટેની ઍપ ચાલુ કરો"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ઑફિસ માટેની ઍપ અને સંપર્કોને ઍક્સેસ કરવા માટે ઑફિસ માટેની ઍપ ચાલુ કરો"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"કોઈ ઍપ ઉપલબ્ધ નથી"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"અમે કોઈપણ ઍપ શોધી શક્યાં નથી"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"ઑફિસ માટેની પ્રોફાઇલ પર સ્વિચ કરો"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ટેલિફોની કૉલમાં ઑડિયો રેકૉર્ડ કરો અથવા ચલાવો"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ડિફૉલ્ટ ડાયલર ઍપ તરીકે સોંપણી કરવામાં આવવા પર આ ઍપને ટેલિફોની કૉલમાં ઑડિયો રેકૉર્ડ કરવાની અથવા ચલાવવાની મંજૂરી આપે છે."</string> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 989cb15f2c1d..eab79c0d8168 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -195,6 +195,14 @@ <skip /> <!-- no translation found for location_changed_notification_text (198907268219396399) --> <skip /> + <!-- no translation found for country_detector (7023275114706088854) --> + <skip /> + <!-- no translation found for location_service (2439187616018455546) --> + <skip /> + <!-- no translation found for sensor_notification_service (7474531979178682676) --> + <skip /> + <!-- no translation found for twilight_service (8964898045693187224) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string> <string name="factory_reset_message" msgid="2657049595153992213">"एडमिन ऐप्लिकेशन का इस्तेमाल नहीं किया जा सकता. आपके डिवाइस पर मौजूद डेटा अब मिटा दिया जाएगा.\n\nअगर आप कुछ पूछना चाहते हैं तो, अपने संगठन के एडमिन से संपर्क करें."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ने प्रिंटिंग सुविधा बंद कर दी है."</string> @@ -247,6 +255,10 @@ <item quantity="one">गड़बड़ी की रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्क्रीनशॉट लिया जा रहा है.</item> <item quantity="other">गड़बड़ी की रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्क्रीनशॉट लिया जा रहा है.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"साइलेंट मोड (खामोश)"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ध्वनि बंद है"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ध्वनि चालू है"</string> @@ -549,8 +561,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"फिर से प्रयास करें."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"फ़िंगरप्रिंट <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +605,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"चेहरा नहीं पहचान पा रहे. फिर से कोशिश करें."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"आपने \'मालिक का चेहरा पहचानकर अनलॉक\' सेट नहीं की है."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"इस डिवाइस पर \'मालिक का चेहरा पहचानकर अनलॉक\' काम नहीं करती है."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> <string name="face_name_template" msgid="3877037340223318119">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1321,6 +1331,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"यूएसबी डीबग करने के लिए एडीबी कनेक्ट किया गया"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"यूएसबी को डीबग करने की सुविधा बंद करने के लिए टैप करें"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB डीबग करना अक्षम करने के लिए चुनें."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस तरीके से डीबग करने की सुविधा फ़ोन से कनेक्ट है"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस तरीके से डीबग करने की सुविधा बंद करने के लिए टैप करें"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस तरीके से डीबग करने की सुविधा बंद करने के लिए चुनें."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"टेस्ट हार्नेस मोड चालू किया गया"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"टेस्ट हार्नेस मोड बंद करने के लिए फ़ैक्ट्री रीसेट करें."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"सीरियल कंसोल को चालू करें"</string> @@ -1624,8 +1637,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>से बैकग्राउंड में शुरू की गई फ़ॉरग्राउंड सेवा के लिए, भविष्य के R बिल्ड में \'इस्तेमाल के समय अनुमति दें\' की सुविधा नहीं होगी. कृपया go/r-bg-fgs-restriction देखें और गड़बड़ी की शिकायत करें."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"वॉल्यूम को सुझाए गए स्तर से ऊपर बढ़ाएं?\n\nअत्यधिक वॉल्यूम पर ज़्यादा समय तक सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"सुलभता शॉर्टकट का इस्तेमाल करना चाहते हैं?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट के चालू होने पर, दाेनाें वॉल्यूम बटन (आवाज़ कम या ज़्यादा करने वाले बटन) को तीन सेकंड तक दबाने से, सुलभता सुविधा शुरू हाे जाएगी."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"शॉर्टकट में बदलाव करें"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"अभी नहीं"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"शॉर्टकट बंद करें"</string> @@ -1848,6 +1860,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"बिना किसी श्रेणी के"</string> <string name="importance_from_user" msgid="2782756722448800447">"आपने इन सूचनाओं की अहमियत सेट की है."</string> <string name="importance_from_person" msgid="4235804979664465383">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के नाम से एक नया उपयोगकर्ता बनाने की अनुमति दें (इस नाम से एक खाता पहले से मौजूद है)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"भाषा जोड़ें"</string> @@ -2021,20 +2035,16 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"निजी प्रोफ़ाइल"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"वर्क प्रोफ़ाइल"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन के साथ चीज़ें शेयर नहीं की जा सकतीं"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"निजी ऐप्लिकेशन के साथ कुछ शेयर नहीं किया जा सकता"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"आपके आईटी एडमिन ने निजी ऐप्लिकेशन और ऑफ़िस के काम से जुड़े ऐप्लिकेशन के बीच कुछ शेयर करने की सुविधा पर रोक लगा दी है"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन चालू करें"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ऑफ़िस के काम से जुड़े ऐप्लिकेशन और संपर्क ऐक्सेस करने के लिए, इन ऐप्लिकेशन को चालू करें"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"कोई ऐप्लिकेशन उपलब्ध नहीं है"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"हमें कोई ऐप्लिकेशन नहीं मिला"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"वर्क प्रोफ़ाइल को चालू करें"</string> + <!-- no translation found for permlab_accessCallAudio (1682957511874097664) --> <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> + <!-- no translation found for permdesc_accessCallAudio (8448360894684277823) --> <skip /> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index cd8eae5a9091..5b7ec23752ca 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -195,6 +195,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može nadzirati mrežni promet. Dodirnite za pojedinosti."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Postavke lokacije koje je promijenio administrator"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Dodirnite da biste vidjeli svoje postavke lokacije."</string> + <string name="country_detector" msgid="7023275114706088854">"Detektor zemlje"</string> + <string name="location_service" msgid="2439187616018455546">"Usluga lokacije"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Usluga Obavijesti senzora"</string> + <string name="twilight_service" msgid="8964898045693187224">"Usluga Sumrak"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorska aplikacija ne može se upotrebljavati. Uređaj će se izbrisati.\n\nAko imate pitanja, obratite se administratoru organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ispis je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -248,6 +252,10 @@ <item quantity="few">Izrada snimke zaslona za izvješće o programskoj pogrešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item> <item quantity="other">Izrada snimke zaslona za izvješće o programskoj pogrešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundi.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Bešumni način"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je isključen"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je uključen"</string> @@ -549,8 +557,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Pokušajte ponovo."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registriran nijedan otisak prsta."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +601,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Lice nije potvrđeno. Pokušajte ponovo."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Niste postavili otključavanje licem"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string> <string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1338,6 +1344,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Priključen je alat za otklanjanje pogrešaka putem USB-a"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Dodirnite da isključite otklanjanje pogrešaka putem USB-a"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Odaberite da biste onemogućili rješavanje programske pogreške na USB-u."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Bežično otklanjanje pogrešaka povezano"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Dodirnite da biste isključili bežično otklanjanje pogrešaka"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Odaberite da biste onemogućili bežično otklanjanje pogrešaka."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Omogućen je način testnog okvira"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Vratite na tvorničke postavke da biste onemogućili način testnog okvira."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serijska konzola omogućena"</string> @@ -1643,8 +1652,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluga u prednjem planu s <xliff:g id="PACKAGENAME">%1$s</xliff:g> pokrenuta u pozadini neće imati dopuštenje tijekom upotrebe u budućim R kompilacijama. Pogledajte go/r-bg-fgs-restriction i pošaljite izvješće o programskoj pogrešci."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li upotrebljavati prečac za pristupačnost?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad je taj prečac uključen, pritiskom na obje tipke za glasnoću na tri sekunde pokrenut će se značajka pristupačnosti."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi prečace"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Otkaži"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Isključi prečac"</string> @@ -1877,6 +1885,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Nema kategorije"</string> <string name="importance_from_user" msgid="2782756722448800447">"Postavili ste važnost tih obavijesti."</string> <string name="importance_from_person" msgid="4235804979664465383">"Važno je zbog uključenih osoba."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Dodavanje jezika"</string> @@ -2052,20 +2062,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobno"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Dijeljenje s poslovnim aplikacijama nije moguće"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Dijeljenje s osobnim aplikacijama nije moguće"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Vaš IT administrator blokirao je dijeljenje između osobnih i poslovnih aplikacija"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Uključite poslovne aplikacije"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Uključite poslovne aplikacije da biste pristupili poslovnim aplikacijama i kontaktima"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Aplikacije nisu dostupne"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nismo pronašli nijednu aplikaciju"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Prebaci na poslovni profil"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snimanje ili reprodukcija zvuka u telefonskim pozivima"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Kad je ova aplikacija postavljena kao zadana aplikacija za biranje, omogućuje joj snimanje ili reprodukciju zvuka u telefonskim pozivima."</string> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index bb1ad3230fe7..a474ac776245 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Ezt az eszközt szervezete kezeli, és lehetséges, hogy a hálózati forgalmat is figyelik. További részletekért koppintson."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"A helybeállításokat módosította a adminisztrátora"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Koppintson a helybeállítások megtekintéséhez."</string> + <string name="country_detector" msgid="7023275114706088854">"Országfelismerő"</string> + <string name="location_service" msgid="2439187616018455546">"Helyszolgáltatás"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Szenzoros értesítési szolgáltatás"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight szolgáltatás"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string> <string name="factory_reset_message" msgid="2657049595153992213">"A rendszergazdai alkalmazás nem használható. A rendszer most törli az eszközt.\n\nKérdéseivel forduljon szervezete rendszergazdájához."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"A(z) <xliff:g id="OWNER_APP">%s</xliff:g> letiltotta a nyomtatást."</string> @@ -245,6 +249,10 @@ <item quantity="other">Képernyőkép készítése a hibajelentéshez <xliff:g id="NUMBER_1">%d</xliff:g> másodpercen belül.</item> <item quantity="one">Képernyőkép készítése a hibajelentéshez <xliff:g id="NUMBER_0">%d</xliff:g> másodpercen belül.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Néma üzemmód"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Hang kikapcsolva"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Hang bekapcsolva"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Próbálkozzon újra."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nincsenek regisztrált ujjlenyomatok."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Az érzékelő átmenetileg le van tiltva."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nem sikerült ellenőrizni az arcát. Próbálja újra."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nem állította be az arcalapú feloldást."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Az eszköz nem támogatja az arcalapú feloldást"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Az érzékelő átmenetileg le van tiltva."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> arc"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-hibakereső csatlakoztatva"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Koppintson az USB-hibakeresés kikapcsolásához"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Válassza ezt az USB hibakeresés kikapcsolásához."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Vezeték nélküli hibakereső csatlakoztatva"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Koppintson a vezeték nélküli hibakeresés kikapcsolásához"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Válassza ezt a vezeték nélküli hibakeresés letiltásához."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Tesztelési alapkörnyezet mód engedélyezve"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"A Tesztelési alapkörnyezet mód kikapcsolásához állítsa vissza a gyári beállításokat."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Soros konzol engedélyezve"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"A háttér által indított előtérben futó szolgáltatás (innen: <xliff:g id="PACKAGENAME">%1$s</xliff:g>) nem tartalmaz majd használat közbeni engedélyt a jövőbeli R buildekben. Kérjük, keresse fel a go/r-bg-fgs-restriction webhelyet, és jelentse a hibát."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Az ajánlott szint fölé szeretné emelni a hangerőt?\n\nHa hosszú időn át teszi ki magát nagy hangerőnek, azzal károsíthatja a hallását."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Szeretné használni a Kisegítő lehetőségek billentyűparancsot?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ha a gyorsparancs aktív, akkor a két hangerőgomb három másodpercig tartó együttes lenyomásával kisegítő funkciót indíthat el."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Gyorsparancsszerkesztés"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Mégse"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Billentyűparancs kikapcsolása"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Nincs kategóriába sorolva"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ön állította be ezen értesítések fontossági szintjét."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ez az üzenet a résztvevők miatt fontos."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal? (Már létezik felhasználó ezzel a fiókkal.)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string> <string name="language_selection_title" msgid="52674936078683285">"Nyelv hozzáadása"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Személyes"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Munka"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nem lehetséges a munkahelyi alkalmazásokkal való megosztás"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nem lehetséges a személyes alkalmazásokkal való megosztás"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Rendszergazdája letiltotta a személyes és a munkahelyi alkalmazások közti megosztást"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Kapcsolja be a munkahelyi alkalmazásokat"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Kapcsolja be a munkahelyi alkalmazásokat a munkahelyi alkalmazásokhoz és a névjegyekhez való hozzáférés érdekében"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nem áll rendelkezésre alkalmazás"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nem találtunk egy alkalmazást sem"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Munkaprofil bekapcsolása"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Audiotartalmak felvétele és lejátszása telefonhívások közben"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Lehetővé teszi ennek az alkalmazásnak audiotartalmak felvételét és lejátszását telefonhívások közben, amennyiben az alkalmazás alapértelmezett tárcsázóalkalmazásként van kijelölve."</string> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index aabfc80fe8fa..80b7985c5a11 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Ձեր կազմակերպությունը կառավարում է այս սարքը և կարող է վերահսկել ցանցի թրաֆիկը: Հպեք՝ մանրամասները դիտելու համար:"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Տեղադրության կարգավորումները փոփոխվել են ձեր ադմինիստրատորի կողմից։"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Հպեք՝ ձեր տեղադրության կարգավորումները տեսնելու համար։"</string> + <string name="country_detector" msgid="7023275114706088854">"Երկրի որոշում"</string> + <string name="location_service" msgid="2439187616018455546">"Տեղորոշման ծառայություն"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Տվիչների ծանուցումների մշակման ծառայություն"</string> + <string name="twilight_service" msgid="8964898045693187224">"Մթնշաղի սկիզբը որոշող ծառայություն"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string> @@ -245,6 +249,10 @@ <item quantity="one">Սքրինշոթը կարվի <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:</item> <item quantity="other">Սքրինշոթը կարվի <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Անձայն ռեժիմ"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ձայնը անջատված է"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ձայնը միացված է"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Փորձեք նորից:"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Գրանցված մատնահետք չկա:"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Տվիչը ժամանակավորապես անջատված է:"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Չհաջողվեց հաստատել դեմքը։ Նորից փորձեք։"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Դուք չեք կարգավորել դեմքով ապակողպումը:"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Դեմքով ապակողպումն այս սարքում չի աջակցվում"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Տվիչը ժամանակավորապես անջատված է:"</string> <string name="face_name_template" msgid="3877037340223318119">"Դեմք <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-ով վրիպազերծումը միացված է"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Հպեք՝ USB-ով վրիպազերծումն անջատելու համար"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Սեղմեք՝ USB-ով վրիպազերծումն անջատելու համար:"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Անլար վրիպազերծումը միացված է"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Հպեք՝ անլար վրիպազերծումն անջատելու համար"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Սեղմեք՝ անլար վրիպազերծումն անջատելու համար:"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Թեստային ռեժիմը միացված է"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Թեստային ռեժիմն անջատելու համար զրոյացրեք կարգավորումները։"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Սերիական վահանակը միացված է"</string> @@ -1542,7 +1551,7 @@ <string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Ընտրել գործունեությունը"</string> <string name="share_action_provider_share_with" msgid="1904096863622941880">"Կիսվել"</string> <string name="sending" msgid="206925243621664438">"Ուղարկվում է..."</string> - <string name="launchBrowserDefault" msgid="6328349989932924119">"Գործարկե՞լ զննարկիչը:"</string> + <string name="launchBrowserDefault" msgid="6328349989932924119">"Գործարկե՞լ դիտարկիչը:"</string> <string name="SetupCallDefault" msgid="5581740063237175247">"Ընդունե՞լ զանգը:"</string> <string name="activity_resolver_use_always" msgid="5575222334666843269">"Միշտ"</string> <string name="activity_resolver_set_always" msgid="4142825808921411476">"Միշտ բացել"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ֆոնային ռեժիմում <xliff:g id="PACKAGENAME">%1$s</xliff:g>-ից գործարկված առաջին պլանի ծառայությունը հետագա R կառուցումներում թույլտվություն չի ունենա օգտագործման ընթացքում։ Անցեք go/r-bg-fgs-restriction էջ և հաղորդեք վրիպակի մասին։"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ձայնը բարձրացնե՞լ խորհուրդ տրվող մակարդակից ավել:\n\nԵրկարատև բարձրաձայն լսելը կարող է վնասել ձեր լսողությունը:"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Օգտագործե՞լ Մատչելիության դյուրանցումը։"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է:"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Փոփոխել դյուրանցումները"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Չեղարկել"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Անջատել դյուրանցումը"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Չդասակարգված"</string> <string name="importance_from_user" msgid="2782756722448800447">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string> <string name="importance_from_person" msgid="4235804979664465383">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել (նման հաշվով Օգտատեր արդեն գոյություն ունի):"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել:"</string> <string name="language_selection_title" msgid="52674936078683285">"Ավելացնել լեզու"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Անձնական"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Աշխատանքային"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Հնարավոր չէ կիսվել աշխատանքային հավելվածների հետ"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Հնարավոր չէ կիսվել անձնական հավելվածների հետ"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ձեր ՏՏ ադմինիստրատորն արգելափակել է աշխատանքային և անձնական հավելվածների միջև տվյալների փոխանակումը։"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Միացրեք աշխատանքային հավելվածները"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Միացրեք աշխատանքային հավելվածները, որպեսզի կարողանաք օգտագործել աշխատանքային տվյալները (հավելվածներն ու կոնտակտները)"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Հասանելի հավելվածներ չկան"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Չհաջողվեց գտնել հավելվածներ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Անցնել աշխատանքային հաշվին"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Հեռախոսային զանգերի ձայնագրում և նվագարկում"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Եթե այս հավելվածն ըստ կանխադրման օգտագործվում է զանգերի համար, այն կարող է ձայնագրել և նվագարկել հեռախոսային խոսակցությունները։"</string> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 7963ba7f67a9..d45370aa4ace 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi mengelola perangkat ini dan mungkin memantau traffic jaringan. Ketuk untuk melihat detailnya."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Setelan lokasi diubah oleh admin Anda"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Ketuk untuk melihat setelan lokasi Anda."</string> + <string name="country_detector" msgid="7023275114706088854">"Pendeteksi Negara"</string> + <string name="location_service" msgid="2439187616018455546">"Layanan Lokasi"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Layanan Notifikasi Sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Layanan Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikasi admin tidak dapat digunakan. Perangkat Anda kini akan dihapus.\n\nJika ada pertanyaan, hubungi admin organisasi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Fitur pencetakan dinonaktifkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Mengambil screenshot untuk laporan bug dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik.</item> <item quantity="one">Mengambil screenshot untuk laporan bug dalam <xliff:g id="NUMBER_0">%d</xliff:g> detik.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mode senyap"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Suara MATI"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Suara AKTIF"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Coba lagi."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tidak ada sidik jari yang terdaftar."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor dinonaktifkan untuk sementara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Tidak dapat memverifikasi wajah. Coba lagi."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Anda belum menyiapkan face unlock."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock tidak didukung di perangkat ini."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor dinonaktifkan untuk sementara."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> wajah"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Proses debug USB terhubung"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Ketuk untuk menonaktifkan proses debug USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Pilih untuk menonaktifkan debugging USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Proses debug nirkabel terhubung"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Ketuk untuk menonaktifkan proses debug nirkabel."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Pilih untuk menonaktifkan proses debug nirkabel."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Mode Tes Otomatis diaktifkan"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Lakukan reset ke setelan pabrik untuk menonaktifkan Mode Tes Otomatis."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Konsol serial diaktifkan"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Layanan latar depan yang dimulai oleh latar belakang dari <xliff:g id="PACKAGENAME">%1$s</xliff:g> tidak akan memiliki izin saat-sedang-digunakan pada build R masa mendatang Lihat go/r-bg-fgs-restriction dan kirim laporan bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Mengeraskan volume di atas tingkat yang disarankan?\n\nMendengarkan dengan volume keras dalam waktu yang lama dapat merusak pendengaran Anda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Aksesibilitas?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Batal"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Nonaktifkan Pintasan"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Belum dikategorikan"</string> <string name="importance_from_user" msgid="2782756722448800447">"Anda menyetel nilai penting notifikasi ini."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ini penting karena orang-orang yang terlibat."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akun ini sudah ada) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pribadi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Tidak dapat membagikan ke aplikasi kerja"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Tidak dapat membagikan ke aplikasi pribadi"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Admin IT memblokir berbagi antara aplikasi kerja dan pribadi"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktifkan aplikasi kerja"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktifkan aplikasi kerja untuk mengakses aplikasi kerja & kontak"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Tidak ada aplikasi yang tersedia"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Kami tidak menemukan aplikasi"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktifkan profil kerja"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Rekam atau putar audio dalam panggilan telepon"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Mengizinkan aplikasi ini, saat ditetapkan sebagai aplikasi telepon default, untuk merekam atau memutar audio dalam panggilan telepon."</string> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index b128e53b8b09..342f6f20f907 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Fyrirtækið þitt stjórnar þessu tæki og kann að fylgjast með netnotkun. Ýttu hér til að fá upplýsingar."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Stjórnandi breytti staðsetningarstillingum"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Ýttu til að sjá staðsetningarstillingar."</string> + <string name="country_detector" msgid="7023275114706088854">"Landsgreining"</string> + <string name="location_service" msgid="2439187616018455546">"Staðsetningarþjónusta"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Tilkynningaþjónusta nema"</string> + <string name="twilight_service" msgid="8964898045693187224">"Ljósaskiptaþjónusta"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Ekki er hægt að nota stjórnunarforritið. Tækinu verður eytt.\n\nEf spurningar vakna skaltu hafa samband við kerfisstjóra fyrirtækisins."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> lokaði á prentun."</string> @@ -245,6 +249,10 @@ <item quantity="one">Tekur skjámynd fyrir villutilkynningu eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndu.</item> <item quantity="other">Tekur skjámynd fyrir villutilkynningu eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Hljóðlaus stilling"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"SLÖKKT er á hljóði"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"KVEIKT er á hljóði"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Reyndu aftur."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Engin fingraför hafa verið skráð."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Slökkt tímabundið á skynjara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ekki tókst að staðfesta andlit. Reyndu aftur."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Þú hefur ekki sett upp andlitsopnun."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Andlitsopnun er ekki studd í þessu tæki."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Slökkt tímabundið á skynjara."</string> <string name="face_name_template" msgid="3877037340223318119">"Andlit <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-villuleit tengd"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Ýttu til að slökkva á USB-villuleit"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Veldu til að gera USB-villuleit óvirka."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Þráðlaus villuleit tengd"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Ýttu til að slökkva á þráðlausri villuleit"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Veldu til að slökkva á þráðlausri villuleit."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Kveikt á stillingu prófunarvangs"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Núllstilltu til að slökkva á stillingu prófunarvangs."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Raðstjórnborð virkjað"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Forgrunnsþjónusta frá <xliff:g id="PACKAGENAME">%1$s</xliff:g> sem er ræst úr bakgrunni mun ekki hafa heimild við notkun í framtíðarútgáfum R. Farðu á go/r-bg-fgs-restriction og gefðu villuskýrslu."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Hækka hljóðstyrk umfram ráðlagðan styrk?\n\nEf hlustað er á háum hljóðstyrk í langan tíma kann það að skaða heyrnina."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Viltu nota aðgengisflýtileið?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Breyta flýtileiðum"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Hætta við"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Slökkva á flýtileið"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Óflokkað"</string> <string name="importance_from_user" msgid="2782756722448800447">"Þú stilltir mikilvægi þessara tilkynninga."</string> <string name="importance_from_person" msgid="4235804979664465383">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Viltu leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> (notandi með þennan reikning er þegar fyrir hendi)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Bæta við tungumáli"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persónulegt"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Vinna"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ekki er hægt að deila með vinnuforritum"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ekki er hægt að deila með persónulegum forritum"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Kerfisstjórinn þinn hefur lokað á deilingu milli persónulegra forrita og vinnuforrita"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Kveikja á vinnuforritum"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Kveiktu á vinnuforritum til að fá aðgang að þeim og vinnutengiliðum"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Engin forrit í boði"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Við fundum engin forrit"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Skipta yfir í vinnu"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Taka upp eða spila hljóð í símtölum"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Gerir þessu forriti kleift að taka upp og spila hljóð í símtölum þegar það er valið sem sjálfgefið hringiforrit."</string> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index b8515df6c02d..783e45ed33b2 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Questo dispositivo è gestito dalla tua organizzazione, che potrebbe monitorare il traffico di rete. Tocca per i dettagli."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Impostazioni di geolocalizzazione modificate dal tuo amministratore"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tocca per vedere le tue impostazioni di geolocalizzazione."</string> + <string name="country_detector" msgid="7023275114706088854">"Rilevatore paese"</string> + <string name="location_service" msgid="2439187616018455546">"Servizio di geolocalizzazione"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Servizio di notifica dei sensori"</string> + <string name="twilight_service" msgid="8964898045693187224">"Servizio Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi.</item> <item quantity="one">Lo screenshot per la segnalazione di bug verrà acquisito tra <xliff:g id="NUMBER_0">%d</xliff:g> secondo.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modalità silenziosa"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Audio non attivo"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Audio attivo"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Riprova."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nessuna impronta digitale registrata."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensore temporaneamente disattivato."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Impossibile verificare il volto. Riprova."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Non hai configurato Sblocco con il volto."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Sblocco con il volto non supportato su questo dispositivo."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensore temporaneamente disattivato."</string> <string name="face_name_template" msgid="3877037340223318119">"Volto <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Debug USB collegato"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tocca per disattivare il debug USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleziona per disattivare il debug USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Debug wireless connesso"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tocca per disattivare il debug wireless"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Seleziona per disattivare il debug wireless."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modalità test harness attivata"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Ripristina le impostazioni di fabbrica per disattivare la modalità test harness."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Console seriale attivata"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Il servizio in primo piano avviato in background da <xliff:g id="PACKAGENAME">%1$s</xliff:g> non avrà l\'autorizzazione \"durante l\'uso\" nelle future build R. Visita la pagina go/r-bg-fgs-restriction e invia una segnalazione di bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usare la scorciatoia Accessibilità?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Modifica scorciatoie"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annulla"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Disattiva scorciatoia"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Senza categoria"</string> <string name="importance_from_user" msgid="2782756722448800447">"Stabilisci tu l\'importanza di queste notifiche."</string> <string name="importance_from_person" msgid="4235804979664465383">"Importante a causa delle persone coinvolte."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g> (esiste già un utente con questo account)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Aggiungi una lingua"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personale"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Lavoro"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Impossibile condividere con app di lavoro"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Impossibile condividere con app personali"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Il tuo amministratore IT ha bloccato la condivisione tra app personali e di lavoro"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Attiva app di lavoro"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Attiva le app di lavoro per accedere alle app e ai contatti di lavoro"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nessuna app disponibile"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nessuna app trovata"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Attiva profilo di lavoro"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Registrazione o riproduzione dell\'audio delle telefonate"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Consente a questa app, se assegnata come applicazione telefono predefinita, di registrare o riprodurre l\'audio delle telefonate."</string> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 4886b4a4385b..b2b56578d527 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"הארגון שלך מנהל מכשיר זה ועשוי לנטר את התנועה ברשת. הקש לקבלת פרטים."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"מנהל המערכת שינה את הגדרות המיקום"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"יש להקיש כדי לראות את הגדרות המיקום שלך."</string> + <string name="country_detector" msgid="7023275114706088854">"גלאי מדינה"</string> + <string name="location_service" msgid="2439187616018455546">"שירות מיקום"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"שירות להתראות מחיישנים"</string> + <string name="twilight_service" msgid="8964898045693187224">"שירות דמדומים"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string> <string name="factory_reset_message" msgid="2657049595153992213">"לא ניתן להשתמש באפליקציה של מנהל המערכת.\n\nאם יש לך שאלות, יש ליצור קשר עם מנהל המערכת של הארגון."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -251,6 +255,10 @@ <item quantity="other">יוצר צילום מסך לדוח על באג בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות.</item> <item quantity="one">יוצר צילום מסך לדוח על באג בעוד שנייה <xliff:g id="NUMBER_0">%d</xliff:g>.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"מצב שקט"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"הקול כבוי"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"קול מופעל"</string> @@ -437,7 +445,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"לאפליקציית המערכת | הזו יש הרשאות מיוחדות והיא יכולה לצלם תמונות ולהקליט סרטונים באמצעות מצלמת מערכת בכל זמן. בנוסף, לאפליקציה נדרשת ההרשאה android.permission.CAMERA"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"שליטה ברטט"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"מאפשר לאפליקציה לשלוט ברטט."</string> - <string name="permdesc_vibrator_state" msgid="7050024956594170724">"מאפשרת לאפליקציה לקבל גישה למצב הרטט."</string> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"מאפשרת לאפליקציה לקבל גישה למצב רטט."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"התקשר ישירות למספרי טלפון"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"מאפשר לאפליקציה להתקשר למספרי טלפון ללא התערבותך. פעולה זו עשויה לגרום לשיחות או לחיובים לא צפויים. שים לב שהדבר לא מאפשר לאפליקציה להתקשר למספרי חירום. אפליקציות זדוניות עשויות לגרום לעלויות על ידי ביצוע שיחות ללא התערבותך."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"גישה אל שירות שיחות IMS"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"כדאי לנסות שוב."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"לא נרשמו טביעות אצבע."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר זה אין חיישן טביעות אצבע."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"החיישן מושבת באופן זמני."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"לא ניתן לאמת את הפנים. יש לנסות שוב."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"לא הגדרת שחרור נעילה על ידי זיהוי פנים."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"המכשיר הזה לא תומך בשחרור נעילה על ידי זיהוי פנים."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"החיישן מושבת באופן זמני."</string> <string name="face_name_template" msgid="3877037340223318119">"פנים <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"ניפוי באגים של USB מחובר"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"יש להקיש כדי לכבות את ניפוי הבאגים ב-USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"בחר להשבית ניפוי באגים ב-USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ניפוי הבאגים האלחוטי מחובר"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"יש להקיש כדי להשבית ניפוי באגים אלחוטי"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"יש לבחור כדי להשבית ניפוי באגים אלחוטי."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"מצב מסגרת בדיקה הופעל"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"כדי להשבית את מצב מסגרת בדיקה צריך לאפס להגדרות היצרן."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"קונסולה סדרתית מופעלת"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"לשירות שפועל בחזית מ-<xliff:g id="PACKAGENAME">%1$s</xliff:g> שהחל ברקע לא תהיה הרשאת while-in-use בגרסאות R build בעתיד. יש לעיין בכתובת go/r-bg-fgs-restriction ולהגיש דוח על באג."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"האם להעלות את עוצמת הקול מעל לרמה המומלצת?\n\nהאזנה בעוצמת קול גבוהה למשכי זמן ממושכים עלולה לפגוע בשמיעה."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"להשתמש בקיצור הדרך לתכונת הנגישות?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת הקול למשך שלוש שניות מפעילה את תכונת הנגישות."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"עריכת קיצורי הדרך"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ביטול"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"כבה את קיצור הדרך"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"ללא שיוך לקטגוריה"</string> <string name="importance_from_user" msgid="2782756722448800447">"עליך להגדיר את החשיבות של ההתראות האלה."</string> <string name="importance_from_person" msgid="4235804979664465383">"ההודעה חשובה בשל האנשים המעורבים."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> (כבר קיים משתמש לחשבון הזה) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"הוספת שפה"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"אישי"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"עבודה"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"לא ניתן לשתף עם אפליקציות לעבודה"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"לא ניתן לשתף עם אפליקציות פרטיות"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"השיתוף בין אפליקציות לעבודה לאפליקציות פרטיות נחסמה על ידי מנהל ה-IT"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"הפעלה של אפליקציות לעבודה"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"יש להפעיל אפליקציות לעבודה כדי לגשת אל אפליקציות ואנשי קשר לעבודה"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"אין אפליקציות זמינות"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"לא מצאנו אפליקציות"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"הפעלה לעבודה"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"הקלטה או הפעלה של אודיו בשיחות טלפוניות"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"כאשר האפליקציה הזו מוגדרת כאפליקציית חייגן בברירת מחדל, תהיה לה הרשאה להקליט ולהפעיל אודיו בשיחות טלפוניות."</string> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 9de16722b1fa..850f6016af96 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"このデバイスは組織によって管理され、ネットワーク トラフィックが監視される場合があります。詳しくはタップしてください。"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"位置情報の設定が管理者によって変更されました"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"タップすると位置情報の設定が表示されます。"</string> + <string name="country_detector" msgid="7023275114706088854">"国の検出"</string> + <string name="location_service" msgid="2439187616018455546">"位置情報サービス"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"センサー通知サービス"</string> + <string name="twilight_service" msgid="8964898045693187224">"トワイライト サービス"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string> <string name="factory_reset_message" msgid="2657049595153992213">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string> @@ -245,6 +249,10 @@ <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item> <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"マナーモード"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"サウンドOFF"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"サウンドON"</string> @@ -431,7 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"権限を付与されたこのシステムアプリは、いつでもシステムカメラを使用して写真と動画を撮影できます。アプリには android.permission.CAMERA 権限も必要です"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"バイブレーションの制御"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"バイブレーションの制御をアプリに許可します。"</string> - <string name="permdesc_vibrator_state" msgid="7050024956594170724">"バイブレーションの状態へのアクセスをアプリに許可します。"</string> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"バイブレーションのオン / オフ状態の把握をアプリに許可します。"</string> <string name="permlab_callPhone" msgid="1798582257194643320">"電話番号発信"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS通話サービスへのアクセス"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"もう一度お試しください。"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"指紋が登録されていません。"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"センサーが一時的に無効になっています。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"指紋 <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"顔を確認できません。もう一度お試しください。"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"顔認証を設定していません。"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"このデバイスでは、顔認証はご利用いただけません。"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"センサーが一時的に無効になっています。"</string> <string name="face_name_template" msgid="3877037340223318119">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USBデバッグが接続されました"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB デバッグを無効にするにはここをタップしてください"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USBデバッグを無効にする場合に選択します。"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ワイヤレス デバッグが接続されました"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ワイヤレス デバッグをUSB デバッグを無効にするにはここをタップしてください"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ワイヤレス デバッグを無効にする場合に選択します。"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"テストハーネス モード有効"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"出荷時設定にリセットしてテストハーネス モードを無効にしてください。"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"シリアル コンソールは有効です"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"今後の R ビルドでは、<xliff:g id="PACKAGENAME">%1$s</xliff:g> からバックグラウンドで開始されるフォアグラウンド サービスに「使用中のみ許可」の権限がありません。go/r-bg-fgs-restriction を確認し、バグレポートを提出してください。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"推奨レベルを超えるまで音量を上げますか?\n\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ユーザー補助機能のショートカットの使用"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ショートカットが ON の場合、両方の音量ボタンを 3 秒ほど長押しするとユーザー補助機能が起動します。"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ショートカットの編集"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"キャンセル"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ショートカットを OFF にする"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"カテゴリなし"</string> <string name="importance_from_user" msgid="2782756722448800447">"このような通知の重要度を設定します。"</string> <string name="importance_from_person" msgid="4235804979664465383">"関係するユーザーのため、この設定は重要です。"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?(このアカウントのユーザーはすでに存在します)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string> <string name="language_selection_title" msgid="52674936078683285">"言語を追加"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人用"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"仕事用"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"仕事用アプリと共有できません"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"個人用アプリと共有できません"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT 管理者が個人用アプリと仕事用アプリの間の共有をブロックしました"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"仕事用アプリを ON にする"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"仕事用のアプリや連絡先にアクセスするには、仕事用アプリを ON にしてください"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"利用できるアプリはありません"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"アプリが見つかりませんでした"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"仕事用に切り替え"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"通話中に録音または音声の再生を行う"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"デフォルトの電話アプリケーションとして割り当てられている場合、このアプリに通話中の録音または音声の再生を許可します。"</string> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 2d15c16afd3b..1ed4854a4155 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ამ მოწყობილობას თქვენი ორგანიზაცია მართავს და მას ქსელის ტრაფიკის მონიტორინგი შეუძლია. შეეხეთ დამატებითი დეტალებისთვის."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"მდებარეობის პარამეტრები თქვენმა ადმინისტრატორმა შეცვალა"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"შეეხეთ თქვენი მდებარეობის პარამეტრების სანახავად."</string> + <string name="country_detector" msgid="7023275114706088854">"ქვეყნის დეტექტორი"</string> + <string name="location_service" msgid="2439187616018455546">"მდებარეობის სერვისი"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"სენსორის შეტყობინების სერვისი"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight სერვისი"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ადმინისტრატორის აპის გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა ახლა ამოიშლება.\n\nთუ შეკითხვები გაქვთ, დაუკავშირდით თქვენი ორგანიზაციის ადმინისტრატორს."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ბეჭდვა გათიშულია <xliff:g id="OWNER_APP">%s</xliff:g>-ის მიერ."</string> @@ -245,6 +249,10 @@ <item quantity="other">ხარვეზის შესახებ ანგარიშის ეკრანის ანაბეჭდის გადაღება მოხდება <xliff:g id="NUMBER_1">%d</xliff:g> წამში.</item> <item quantity="one">ხარვეზის შესახებ ანგარიშის ეკრანის ანაბეჭდის გადაღება მოხდება <xliff:g id="NUMBER_0">%d</xliff:g> წამში.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ჩუმი რეჟიმი"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ხმა გამორთულია"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ხმა ჩართულია"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ხელახლა სცადეთ"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"თითის ანაბეჭდები რეგისტრირებული არ არის."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"სენსორი დროებით გათიშულია."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"თითი <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"სახის დადასტურება ვერ ხერხდება. ცადეთ ხელახლა."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"თქვენ არ დაგიყენებიათ სახით განბლოკვა."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"განბლოკვა სახით ამ მოწყობილობაზე მხარდაჭერილი არ არის."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"სენსორი დროებით გათიშულია."</string> <string name="face_name_template" msgid="3877037340223318119">"სახე <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB გამართვა შეერთებულია"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"შეეხეთ, რათა გამორთოთ USB შეცდომების გამართვა"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"მონიშნეთ რათა შეწყვიტოთ USB-ის გამართვა"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"შეცდომების უსადენო გამართვა დაკავშირებულია"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"შეეხეთ შეცდომების უსადენო გამართვის გამოსართავად"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"აირჩიეთ შეცდომების უსადენო გამართვის გასათიშად."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"რეჟიმი „გარემო ტესტირებისთვის“ ჩართულია"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"დააბრუნეთ ქარხნული პარამეტრები „გარემო ტესტირებისთვის“ რეჟიმის გასათიშად."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"სერიული კონსოლი ჩართულია"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>-ის ფონურად დაწყებულ წინა პლანის სერვისს მომავალ R build-ებში გამოყენების პროცესში წვდომის ნებართვა არ ექნება. გთხოვთ, იხილოთ go/r-bg-fgs-restriction და გამოგზავნოთ ხარვეზის ანგარიში."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"გსურთ ხმის რეკომენდებულ დონეზე მაღლა აწევა?\n\nხანგრძლივად ხმამაღლა მოსმენით შესაძლოა სმენადობა დაიზიანოთ."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"გსურთ მარტივი წვდომის მალსახმობის გამოყენება?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"თუ მალსახმობი ჩართულია, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"მალსახმობების რედაქტირება"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"გაუქმება"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"მალსახმობის გამორთვა"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"კატეგორიის გარეშე"</string> <string name="importance_from_user" msgid="2782756722448800447">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრა თქვენ მიერ."</string> <string name="importance_from_person" msgid="4235804979664465383">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას (ამ ანგარიშის მქონე მომხმარებელი უკვე არსებობს)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას?"</string> <string name="language_selection_title" msgid="52674936078683285">"ენის დამატება"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"პირადი"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"სამსახური"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"სამსახურის აპებით გაზიარება შეუძლებელია"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"პირადი აპებით გაზიარება შეუძლებელია"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"თქვენმა IT ადმინისტრატორმა დაბლოკა გაზიარება პირად და სამსახურის აპებს შორის"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"სამსახურის აპების ჩართვა"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"სამსახურის აპებსა და კონტაქტებზე წვდომისთვის ჩართეთ სამსახურის აპები"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ხელმისაწვდომი აპები არ არის"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"აპები ვერ მოიძებნა"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"სამსახურზე გადართვა"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"სატელეფონო ზარებში აუდიოს ჩაწერა ან დაკვრა"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ნაგულისხმევ დასარეკ აპლიკაციად არჩევის შემთხვევაში, ნებას რთავს აპს ჩაიწეროს ან დაუკრას აუდიო სატელეფონო ზარებში."</string> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 1406a8be9e6e..2e10b16958e5 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -191,10 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"Әкімші құрылғыны жеке пайдалануға ұсынды."</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Құрылғы басқарылады"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ұйымыңыз осы құрылғыны басқарады және желі трафигін бақылауы мүмкін. Мәліметтер алу үшін түртіңіз."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"Орналасу параметрлерін әкімшіңіз өзгертті."</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"Орналасу параметрлерін көру үшін түртіңіз."</string> + <string name="country_detector" msgid="7023275114706088854">"Ел детекторы"</string> + <string name="location_service" msgid="2439187616018455546">"Орынды анықтау қызметі"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Датчик хабарландыруы қызметі"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight қызметі"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Әкімші қолданбасын пайдалану мүмкін емес. Қазір құрылғыдағы деректер өшіріледі\n\nСұрақтарыңыз болса, ұйым әкімшісіне хабарласыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып шығаруды <xliff:g id="OWNER_APP">%s</xliff:g> өшірді."</string> @@ -247,6 +249,10 @@ <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қате туралы есептің скриншоты түсіріледі.</item> <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> секундтан кейін қате туралы есептің скриншоты түсіріледі.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Үнсіз режимі"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Дыбыс ӨШІРУЛІ"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Дыбыс ҚОСУЛЫ"</string> @@ -433,8 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"Осы айрықша | жүйе қолданбасы кез келген уақытта жүйелік камера арқылы суретке не бейнеге түсіре алады. Қолданбаға android.permission.CAMERA рұқсаты қажет болады."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"тербелісті басқару"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Қолданбаға вибраторды басқаруға рұқсат береді."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Қолданбаға діріл күйін пайдалануға мүмкіндік береді."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"нөмірлерге тікелей телефон шалу"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Қолданбаға сіздің қатысуыңызсыз қоңырау шалу мүмкіндігін береді. Нәтижесінде қосымша төлем немесе күтпеген қоңырау алуыңыз мүмкін. Есіңізде болсын, қолданба төтенше байланыстарға қоңырау шала алмайды. Залалды қолданбалар сіздің рұқсатыңызсыз қоңыраулар шалып, күтпеген төлемдерге себеп болуы мүмкін."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS қоңырау қызметін пайдалану"</string> @@ -549,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Әрекетті қайталаңыз."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Саусақ іздері тіркелмеген."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик уақытша өшірулі."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> саусағы"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Бетті тану мүмкін емес. Әрекетті қайталаңыз."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Face Unlock реттелмеді."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Бұл құрылғыда Face Unlock функциясы істемейді."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик уақытша өшірулі."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> беті"</string> <string-array name="face_error_vendor"> </string-array> @@ -1321,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB түзетуі қосылған"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB арқылы түзетуді өшіру үшін түртіңіз"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB түзетуін өшіру үшін таңдаңыз."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Сымсыз түзету байланыстырылды"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Сымсыз түзетуді өшіру үшін түртіңіз."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Сымсыз түзетуді өшіріңіз."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Сынақ бағдарламасы режимі қосылды"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Сынақ бағдарламасы режимін өшіру үшін зауыттық күйіне қайтарыңыз."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Сериялық консоль қосылды"</string> @@ -1624,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Фондық режимде іске қосылған <xliff:g id="PACKAGENAME">%1$s</xliff:g> белсенді пакетінің алдағы R құрамаларында \"Пайдаланғанда ғана рұқсат ету\" рұқсаты болмайды. go/r-bg-fgs-restriction бетіне өтіп, қате туралы есеп жіберіңіз."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дыбыс деңгейін ұсынылған деңгейден көтеру керек пе?\n\nЖоғары дыбыс деңгейінде ұзақ кезеңдер бойы тыңдау есту қабілетіңізге зиян тигізуі мүмкін."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Арнайы мүмкіндік төте жолын пайдалану керек пе?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Түймелер тіркесімі қосулы кезде, екі дыбыс түймесін 3 секунд басып тұрсаңыз, \"Арнайы мүмкіндіктер\" функциясы іске қосылады."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Таңбашаларды өзгерту"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Бас тарту"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Төте жолды өшіру"</string> @@ -1848,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Санатқа жатқызылмаған"</string> <string name="importance_from_user" msgid="2782756722448800447">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string> <string name="importance_from_person" msgid="4235804979664465383">"Қатысты адамдарға байланысты бұл маңызды."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы (мұндай есептік жазбаға ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string> <string name="language_selection_title" msgid="52674936078683285">"Тілді қосу"</string> @@ -2021,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Жұмыс"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Жұмыс қолданбаларымен бөлісілмейді"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Жеке қолданбалармен бөлісілмейді"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"АТ әкімшісі жеке және жұмыс қолданбалары арасында деректер бөлісуді бөгеді."</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Жұмыс қолданбаларын іске қосу"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Жұмыс қолданбаларын және контактілерді пайдалану үшін, оларды іске қосыңыз."</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Қолданбалар жоқ"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Ешқандай қолданба табылмады."</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Жұмыс профилін іске қосу"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Телефон қоңырауларында аудио жазу немесе ойнату"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Қолданба әдепкі нөмір тергіш қолданба ретінде тағайындалған кезде, телефон қоңырауларында аудионы жазуға немесе ойнатуға мүмкіндік береді."</string> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 50e2e1541ec8..ce8983276023 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ស្ថាប័នរបស់អ្នកគ្រប់គ្រងឧបករណ៍នេះ ហើយអាចនឹងតាមដានចរាចរណ៍បណ្តាញ។ ចុចដើម្បីទទួលបានព័ត៌មានលម្អិត។"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"ការកំណត់ទីតាំងត្រូវបានប្ដូរដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"ចុចដើម្បីមើលការកំណត់ទីតាំងរបស់អ្នក។"</string> + <string name="country_detector" msgid="7023275114706088854">"ឧបករណ៍សម្គាល់ប្រទេស"</string> + <string name="location_service" msgid="2439187616018455546">"សេវាកម្មទីតាំង"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"សេវាកម្មជូនដំណឹងឧបករណ៍ចាប់សញ្ញា"</string> + <string name="twilight_service" msgid="8964898045693187224">"សេវាកម្មព្រលប់"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string> <string name="factory_reset_message" msgid="2657049595153992213">"មិនអាចប្រើកម្មវិធីអ្នកគ្រប់គ្រងបានទេ។ ឧបករណ៍របស់អ្នកនឹងលុបឥឡូវនេះ។\n\nប្រសិនបើអ្នកមានសំណួរផ្សេងៗ សូមទាក់ទងទៅអ្នកគ្រប់គ្រងស្ថាប័នរបស់អ្នក។"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ការបោះពុម្ពត្រូវបានបិទដោយ <xliff:g id="OWNER_APP">%s</xliff:g> ។"</string> @@ -245,6 +249,10 @@ <item quantity="other">នឹងថតរូបអេក្រង់សម្រាប់របាយការណ៍កំហុសក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទីទៀត។</item> <item quantity="one">នឹងថតរូបអេក្រង់សម្រាប់របាយការណ៍កំហុសក្នុងរយៈពេល <xliff:g id="NUMBER_0">%d</xliff:g> វិនាទីទៀត។</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"របៀបស្ងាត់"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"បិទសំឡេង"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"បើកសំឡេង"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ព្យាយាមម្ដងទៀត។"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"មិនមានការចុះឈ្មោះស្នាមម្រាមដៃទេ។"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះមិនមានឧបករណ៍ចាប់ស្នាមម្រាមដៃទេ។"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ម្រាមដៃ <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"មិនអាចផ្ទៀងផ្ទាត់មុខបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"អ្នកមិនទាន់រៀបចំការដោះសោតាមទម្រង់មុខនៅឡើយទេ។"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"មិនអាចប្រើការដោះសោតាមទម្រង់មុខនៅលើឧបករណ៍នេះបានទេ។"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string> <string name="face_name_template" msgid="3877037340223318119">"ផ្ទៃមុខទី <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1320,6 +1326,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"បានភ្ជាប់ការកែកំហុសតាម USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"ចុចដើម្បីបិទការកែកំហុសតាម USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"ជ្រើសរើស ដើម្បីបិទការកែកំហុសតាម USB ។"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"បានភ្ជាប់ការជួសជុលដោយឥតខ្សែ"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ចុច ដើម្បីបិទការជួសជុលដោយឥតខ្សែ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ជ្រើសរើស ដើម្បីបិទការជួសជុលដោយឥតខ្សែ។"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"បានបើកមុខងារប្រមូលធ្វើតេស្ត"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ធ្វើការកំណត់ដូចដើមឡើងវិញ ដើម្បីបិទមុខងារប្រមូលធ្វើតេស្ត។"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"កុងសូលស៊េរីត្រូវបានបើក"</string> @@ -1623,8 +1632,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"សេវាកម្មផ្ទៃខាងមុខដែលចាប់ផ្ដើមដោយផ្ទៃខាងក្រោយពី <xliff:g id="PACKAGENAME">%1$s</xliff:g> នឹងមិនមានការអនុញ្ញាតខណៈពេលកំពុងប្រើប្រាស់ទេ នៅក្នុងកំណែបង្កើត R នៅពេលអនាគត។ សូមមើល go/r-bg-fgs-restriction និងផ្ញើរបាយការណ៍អំពីបញ្ហា។"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"បង្កើនកម្រិតសំឡេងលើសពីកម្រិតបានផ្ដល់យោបល់?\n\nការស្ដាប់នៅកម្រិតសំឡេងខ្លាំងយូរអាចធ្វើឲ្យខូចត្រចៀក។"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ប្រើប្រាស់ផ្លូវកាត់ភាពងាយស្រួល?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"នៅពេលបើកផ្លូវកាត់ ការចុចប៊ូតុងកម្រិតសំឡេងទាំងពីររយៈពេល 3 វិនាទីនឹងចាប់ផ្តើមមុខងារភាពងាយប្រើ។"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"កែផ្លូវកាត់"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"បោះបង់"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"បិទផ្លូវកាត់"</string> @@ -1847,6 +1855,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"មិនបែងចែកប្រភេទ"</string> <string name="importance_from_user" msgid="2782756722448800447">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string> <string name="importance_from_person" msgid="4235804979664465383">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> (អ្នកប្រើប្រាស់ដែលមានគណនីនេះមានរួចហើយ) ដែរឬទេ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ដែរឬទេ?"</string> <string name="language_selection_title" msgid="52674936078683285">"បន្ថែមភាសា"</string> @@ -2020,20 +2030,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ផ្ទាល់ខ្លួន"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ការងារ"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"មិនអាចចែករំលែកជាមួយកម្មវិធីការងារបានទេ"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"មិនអាចចែករំលែកជាមួយកម្មវិធីផ្ទាល់ខ្លួនបានទេ"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកបានទប់ស្កាត់ការចែករំលែករវាងកម្មវិធីការងារ និងផ្ទាល់ខ្លួន"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"បើកកម្មវិធីការងារ"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"បើកកម្មវិធីការងារ ដើម្បីចូលប្រើទំនាក់ទំនង និងកម្មវិធីការងារ"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"មិនមានកម្មវិធីដែលអាចប្រើបានទេ"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"យើងរកមិនឃើញកម្មវិធីណាមួយទេ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"បើកកម្រងព័ត៌មានការងារ"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ថត ឬចាក់សំឡេងនៅក្នុងការហៅទូរសព្ទ"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"នៅពេលកំណត់ជាកម្មវិធីផ្ទាំងចុចហៅទូរសព្ទលំនាំដើម សូមអនុញ្ញាតឱ្យកម្មវិធីនេះថត ឬចាក់សំឡេងនៅក្នុងការហៅទូរសព្ទ។"</string> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 4099d301dbba..93721a5c7a36 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ ಮತ್ತು ಅದು ನೆಟ್ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಮೇಲೆ ಗಮನವಿರಿಸಬಹುದು. ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಸ್ಥಳ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"ನಿಮ್ಮ ಸ್ಥಳ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> + <string name="country_detector" msgid="7023275114706088854">"ಕಂಟ್ರಿ ಡಿಟೆಕ್ಟರ್"</string> + <string name="location_service" msgid="2439187616018455546">"ಸ್ಥಳ ಸೇವೆ"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"ಸೆನ್ಸರ್ ಅಧಿಸೂಚನೆ ಸೇವೆ"</string> + <string name="twilight_service" msgid="8964898045693187224">"ಟ್ವಿಲೈಟ್ ಸೇವೆ"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ನಿರ್ವಹಣೆ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮಲ್ಲಿ ಪ್ರಶ್ನೆಗಳಿದ್ದರೆ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ಮೂಲಕ ಪ್ರಿಂಟಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> @@ -245,6 +249,10 @@ <item quantity="one">ಬಗ್ ವರದಿ ಮಾಡಲು <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ಕ್ರೀನ್ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ.</item> <item quantity="other">ಬಗ್ ವರದಿ ಮಾಡಲು <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ಕ್ರೀನ್ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ಶಾಂತ ಮೋಡ್"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ಶಬ್ಧ ಆಫ್ ಆಗಿದೆ"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ಶಬ್ಧ ಆನ್ ಆಗಿದೆ"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ಯಾವುದೇ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ನೋಂದಣಿ ಮಾಡಿಲ್ಲ."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ಫಿಂಗರ್ <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"ನೀವು ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಸೆಟಪ್ ಮಾಡಿಲ್ಲ."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"ಈ ಸಾಧನದಲ್ಲಿ ಫೇಸ್ ಅನ್ಲಾಕ್ ವೈಶಿಷ್ಟ್ಯವು ಬೆಂಬಲಿತವಾಗಿಲ್ಲ."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string> <string name="face_name_template" msgid="3877037340223318119">"ಮುಖದ <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -876,7 +882,7 @@ <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"ಪ್ಯಾಟರ್ನ್ ಪೂರ್ಣಗೊಂಡಿದೆ"</string> <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"ಪ್ಯಾಟರ್ನ್ ಪ್ರದೇಶ."</string> <string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s.%3$d ರಲ್ಲಿ %2$d ವಿಜೆಟ್."</string> - <string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"ವಿಜೆಟ್ ಸೇರಿಸು."</string> + <string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"ವಿಜೆಟ್ ಸೇರಿಸಿ."</string> <string name="keyguard_accessibility_widget_empty_slot" msgid="544239307077644480">"ಖಾಲಿ"</string> <string name="keyguard_accessibility_unlock_area_expanded" msgid="7768634718706488951">"ಅನ್ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ವಿಸ್ತರಿಸಲಾಗಿದೆ."</string> <string name="keyguard_accessibility_unlock_area_collapsed" msgid="4729922043778400434">"ಅನ್ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ಸಂಕುಚಿಸಲಾಗಿದೆ."</string> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗಿಂಗ್ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ವೈರ್ಲೆಸ್ ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ವೈರ್ಲೆಸ್ ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ವೈರ್ಲೆಸ್ ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವಿಕೆ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವಿಕೆ ಮೋಡ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಫ್ಯಾಕ್ಟರಿ ರಿಸೆಟ್ ಮಾಡಬೇಕು."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ಸರಣಿ ಕನ್ಸೋಲ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> ನಿಂದ ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಪ್ರಾರಂಭಿಸಲಾದ ಮುನ್ನೆಲೆ ಸೇವೆ ಭವಿಷ್ಯದ R ಬಿಲ್ಡ್ಗಳಿಂದ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಅನುಮತಿಯನ್ನು ಪಡೆಯುವುದಿಲ್ಲ. go/r-bg-fgs-restriction ಅನ್ನು ನೋಡಿ ಮತ್ತು ದೋಷವರದಿಯನ್ನು ಫೈಲ್ ಮಾಡಿ."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ವಾಲ್ಯೂಮ್ ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾದ ಮಟ್ಟಕ್ಕಿಂತಲೂ ಹೆಚ್ಚು ಮಾಡುವುದೇ?\n\nದೀರ್ಘ ಅವಧಿಯವರೆಗೆ ಹೆಚ್ಚಿನ ವಾಲ್ಯೂಮ್ನಲ್ಲಿ ಆಲಿಸುವುದರಿಂದ ನಿಮ್ಮ ಆಲಿಸುವಿಕೆ ಸಾಮರ್ಥ್ಯಕ್ಕೆ ಹಾನಿಯುಂಟು ಮಾಡಬಹುದು."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಬಳಸುವುದೇ?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳನ್ನು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಿದರೆ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವೊಂದು ಪ್ರಾರಂಭವಾಗುತ್ತದೆ."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ರದ್ದುಗೊಳಿಸಿ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ಶಾರ್ಟ್ಕಟ್ ಆಫ್ ಮಾಡಿ"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"ವರ್ಗೀಕರಿಸದಿರುವುದು"</string> <string name="importance_from_user" msgid="2782756722448800447">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string> <string name="importance_from_person" msgid="4235804979664465383">"ಜನರು ತೊಡಗಿಕೊಂಡಿರುವ ಕಾರಣ ಇದು ಅತ್ಯಂತ ಪ್ರಮುಖವಾಗಿದೆ."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (ಈ ಖಾತೆಯ ಬಳಕೆದಾರರು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದ್ದಾರೆ) ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೆ ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string> <string name="language_selection_title" msgid="52674936078683285">"ಭಾಷೆ ಸೇರಿಸಿ"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ವೈಯಕ್ತಿಕ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ಕೆಲಸ"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ಕೆಲಸದ ಆ್ಯಪ್ಗಳೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್ಗಳೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ನಿಮ್ಮ ಐಟಿ ನಿರ್ವಾಹಕರು, ವೈಯಕ್ತಿಕ ಮತ್ತು ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳ ನಡುವೆ ಹಂಚಿಕೊಳ್ಳುವುದನ್ನು ನಿರ್ಬಂಧಿಸಿದ್ದಾರೆ"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು, ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಆನ್ ಮಾಡಿ"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ಯಾವುದೇ ಆ್ಯಪ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ನಮಗೆ ಯಾವುದೇ ಆ್ಯಪ್ಗಳನ್ನು ಹುಡುಕಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಆನ್ ಮಾಡಿ"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ಫೋನ್ ಕರೆಗಳಲ್ಲಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ ಅಥವಾ ಪ್ಲೇ ಮಾಡಿ"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ಡೀಫಾಲ್ಟ್ ಡಯಲರ್ ಅಪ್ಲಿಕೇಶನ್ ರೀತಿ ಬಳಸಿದಾಗ ಫೋನ್ ಕರೆಗಳಲ್ಲಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ಅಥವಾ ಪ್ಲೇ ಮಾಡಲು ಈ ಆ್ಯಪ್ ಅನ್ನು ಅನುಮತಿಸಿ."</string> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index bae739c2ef04..7ec0e77ee804 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"조직에서 이 기기를 관리하며 네트워크 트래픽을 모니터링할 수도 있습니다. 자세한 내용을 보려면 탭하세요."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"관리자가 위치 설정을 변경함"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"위치 설정을 보려면 탭하세요."</string> + <string name="country_detector" msgid="7023275114706088854">"국가 감지기"</string> + <string name="location_service" msgid="2439187616018455546">"위치 서비스"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"센서 알림 서비스"</string> + <string name="twilight_service" msgid="8964898045693187224">"새벽 서비스"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string> <string name="factory_reset_message" msgid="2657049595153992213">"관리자 앱을 사용할 수 없습니다. 곧 기기가 삭제됩니다.\n\n궁금한 점이 있으면 조직의 관리자에게 문의하세요."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g>에 의해 사용 중지되었습니다."</string> @@ -245,6 +249,10 @@ <item quantity="other">버그 신고 스크린샷을 <xliff:g id="NUMBER_1">%d</xliff:g>초 후에 찍습니다.</item> <item quantity="one">버그 신고 스크린샷을 <xliff:g id="NUMBER_0">%d</xliff:g>초 후에 찍습니다.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"무음 모드"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"소리 꺼짐"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"소리 켜짐"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"다시 시도해 보세요."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"등록된 지문이 없습니다."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"센서가 일시적으로 사용 중지되었습니다."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"얼굴을 확인할 수 없습니다. 다시 시도하세요."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"얼굴인식 잠금해제를 설정하지 않았습니다."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"이 기기에서는 얼굴인식 잠금해제가 지원되지 않습니다."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"센서가 일시적으로 사용 중지되었습니다."</string> <string name="face_name_template" msgid="3877037340223318119">"얼굴 <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB 디버깅 연결됨"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB 디버깅을 사용 중지하려면 탭하세요."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB 디버깅을 사용하지 않으려면 선택합니다."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"무선 디버깅 연결됨"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"무선 디버깅을 사용 중지하려면 탭하세요."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"무선 디버깅을 사용 중지하려면 선택하세요."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"테스트 하네스 모드 사용 설정됨"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"테스트 하네스 모드를 사용 중지하려면 초기화하세요."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"시리얼 콘솔 사용 설정됨"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"향후 R 빌드에서는 백그라운드에서 시작된 <xliff:g id="PACKAGENAME">%1$s</xliff:g>의 포그라운드 서비스에 더 이상 사용 중인 상태에서 필요한 권한이 부여되지 않습니다. go/r-bg-fgs-restriction 페이지에서 버그 신고를 제출하세요."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"권장 수준 이상으로 볼륨을 높이시겠습니까?\n\n높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"접근성 단축키를 사용하시겠습니까?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"단축키가 사용 설정된 경우 볼륨 버튼 두 개를 동시에 3초간 누르면 접근성 기능이 시작됩니다."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"단축키 수정"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"취소"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"단축키 사용 중지"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"지정된 카테고리 없음"</string> <string name="importance_from_user" msgid="2782756722448800447">"이러한 알림의 중요도를 설정했습니다."</string> <string name="importance_from_person" msgid="4235804979664465383">"관련된 사용자가 있으므로 중요합니다."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까? 이 계정으로 등록된 사용자가 이미 존재합니다."</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까?"</string> <string name="language_selection_title" msgid="52674936078683285">"언어 추가"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"개인"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"직장"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"직장 앱과 공유할 수 없음"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"개인 앱과 공유할 수 없음"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT 관리자가 개인 앱과 직장 앱 간의 공유를 차단함"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"직장 앱 사용 설정"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"직장 앱 및 연락처에 액세스하도록 직장 앱 사용 설정"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"사용 가능한 앱 없음"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"앱을 찾을 수 없음"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"직장 프로필 사용"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"전화 통화 중에 오디오 녹음 또는 재생"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"이 앱이 기본 다이얼러 애플리케이션으로 지정되었을 때 전화 통화 중에 오디오를 녹음하거나 재생하도록 허용합니다."</string> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index e9177abed615..74e03c08f72e 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -191,10 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"Админ түзмөктөн жеке колдонуу үчүн баш тартты"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"Түзмөктү ишкана башкарат"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"Ишканаңыз бул түзмөктү башкарат жана тармак трафигин көзөмөлдөшү мүмкүн. Чоо-жайын билгиңиз келсе, таптап коюңуз."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"Жайгашкан жерди аныктоо жөндөөлөрүн администраторуңуз өзгөртүп койду"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"Жайгашкан жерди аныктоо жөндөөлөрүн көрүү үчүн таптап коюңуз."</string> + <string name="country_detector" msgid="7023275114706088854">"Өлкөнү аныктагыч"</string> + <string name="location_service" msgid="2439187616018455546">"Жайгашкан жерди аныктоо кызматы"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Сенсордун билдирмелеринин кызматы"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight кызматы"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string> @@ -247,6 +249,10 @@ <item quantity="other">Мүчүлүштүк тууралуу кабарлоо үчүн <xliff:g id="NUMBER_1">%d</xliff:g> секундда скриншот алынат.</item> <item quantity="one">Мүчүлүштүк тууралуу кабарлоо үчүн <xliff:g id="NUMBER_0">%d</xliff:g> секундда скриншот алынат.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Үнсүз режим"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Добушу ӨЧҮК"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Добушу КҮЙҮК"</string> @@ -433,12 +439,11 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"Бул артыкчылыктуу | тутум колдонмосу тутумдун камерасын каалаган убакта колдонуп, сүрөткө тартып, видео жаздыра алат. Ошондой эле колдонмого android.permission.CAMERA уруксатын берүү керек."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"титирөөнү башкаруу"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Колдонмого дирилдөө абалына кирүүгө уруксат берет."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"телефон номерлерине түз чалуу"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Колдонмого сиздин катышууңузсуз телефон номурларга чалуу уруксатын берет. Бул сиз күтпөгөн чыгымдарга же чалууларга алып келиши мүмкүн. Бул куткаруучулардын номурларына чалууга уруксат бербей тургандыгын эске алыңыз. Зыяндуу колдонмолор, сиздин ырастооңузсуз чалууларды аткарып, көп чыгымдарга себепкер болушу мүмкүн."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS чалуу кызматына мүмкүнчүлүк алуу"</string> - <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Колдонмого сизди катыштырбай туруп, IMS кызматынын жардамы менен чалууларды жасоо мүмкүнчүлүгүн берет."</string> + <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Колдонмого сизди катыштырбай туруп, IMS кызматынын жардамы менен, чалууларды жасоо мүмкүнчүлүгүн берет."</string> <string name="permlab_readPhoneState" msgid="8138526903259297969">"телефондун абалын жана аныктыгын окуу"</string> <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Колдонмого түзмөктүн чалуу мүмкүнчүлүктөрүнө жетки алуу уруксатын берет. Бул уруксат колдонмого, телефондун номурун, түзмөктүн ID-син, чалуунун абалын жана байланышта чыккан номурду аныктоого жол берет."</string> <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"чалууларды тутум аркылуу өткөрүү"</string> @@ -549,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Кайра бир аракеттениңиз."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бир да манжа изи катталган эмес."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сенсор убактылуу өчүрүлгөн."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-манжа"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Жүз ырасталбай жатат. Кайталап көрүңүз."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Жүзүнөн таануу функциясын жөндөй элексиз."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Жүзүнөн таануу функциясы бул түзмөктө иштебейт."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Сенсор убактылуу өчүрүлгөн."</string> <string name="face_name_template" msgid="3877037340223318119">"Жүз <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1254,7 +1257,7 @@ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> Интернетке туташуусу жок"</string> <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Параметрлерди ачуу үчүн таптап коюңуз"</string> <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилдик Интернет жок"</string> - <string name="other_networks_no_internet" msgid="6698711684200067033">"Тармактын Интернет байланышы жок"</string> + <string name="other_networks_no_internet" msgid="6698711684200067033">"Тармактын Интернет жок"</string> <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS сервери жеткиликсиз"</string> <string name="captive_portal_logged_in_detailed" msgid="3897392681039344376">"Туташты"</string> <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> байланышы чектелген"</string> @@ -1321,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Мүчүлүштүктөрдү USB аркылуу оңдоо иштеп жатат"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Өчүрүү үчүн тийип коюңуз"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB аркылуу мүчүлүштүктөрдү оңдоону өчүрүүнү тандаңыз."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Мүчүлүштүктөрдү зымсыз оңдоо иштетилди"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Мүчүлүштүктөрдү зымсыз оңдоону өчүрүү үчүн таптап коюңуз"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Мүчүлүштүктөрдү зымсыз оңдоону өчүрүүнү тандаңыз."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Сыноо программасынын режими иштетилди"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Сыноо программасынын режимин өчүрүү үчүн, баштапкы жөндөөлөргө кайтарыңыз."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Сериялык консоль иштетилди"</string> @@ -1624,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Фондогу <xliff:g id="PACKAGENAME">%1$s</xliff:g> кызматы активдүү режимде иштеп баштап, кийинки R курамаларында колдонуу учурунда уруксаты болбойт. Төмөнкү бөлүмгө өтүп, мүчүлүштүк тууралуу кабарды тапшырыңыз: go/r-bg-fgs-restriction."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ыкчам иштетесизби?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Кыска жолдорду түзөтүү"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Жокко чыгаруу"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Кыска жолду өчүрүү"</string> @@ -1848,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Категорияларга бөлүнгөн эмес"</string> <string name="importance_from_user" msgid="2782756722448800447">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string> <string name="importance_from_person" msgid="4235804979664465383">"Булар сиз үчүн маанилүү адамдар."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби (мындай аккаунту бар колдонуучу мурунтан эле бар)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби?"</string> <string name="language_selection_title" msgid="52674936078683285">"Тил кошуу"</string> @@ -2021,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Жумуш"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Жумуш колдонмолору менен бөлүшүүгө болбойт"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Жеке колдонмолор менен бөлүшүүгө болбойт"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT администраторуңуз жеке жана жумуш колдонмолорунун ортосунда бөлүшүүнү бөгөттөп койгон"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Жумуш колдонмолорун күйгүзүү"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Жумуш колдонмолоруна жана байланыштарга кирүү үчүн жумуш колдонмолорун күйүгүзүңүз"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Колдонмолор жок"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Эч кандай колдонмо табылган жок"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Жумуш профилине которулуу"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Телефон чалууларда жаздырып же аудиону ойнотуу"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Бул колдонмо демейки телефон катары дайындалганда ага чалууларды жаздырууга жана аудиону ойнотууга уруксат берет."</string> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index ce1725818265..862aa53fe9da 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ອົງກອນຂອງທ່ານຈັດການອຸປະກອນນີ້ ແລະ ອາດກວດສອບທຣາບຟິກເຄືອຂ່າຍນຳ. ແຕະເພື່ອເບິ່ງລາຍລະອຽດ."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"ຜູ້ເບິ່ງແຍງຂອງທ່ານປ່ຽນການຕັ້ງຄ່າສະຖານທີ່ແລ້ວ"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"ແຕະເພື່ອເບິ່ງການຕັ້ງຄ່າສະຖານທີ່ຂອງທ່ານ."</string> + <string name="country_detector" msgid="7023275114706088854">"ຕົວກວດຫາປະເທດ"</string> + <string name="location_service" msgid="2439187616018455546">"ບໍລິການສະຖານທີ່"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"ບໍລິການການແຈ້ງເຕືອນເຊັນເຊີ"</string> + <string name="twilight_service" msgid="8964898045693187224">"ບໍລິການ Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"ອຸປະກອນຂອງທ່ານຈະຖືກລຶບ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ບໍ່ສາມາດໃຊ້ແອັບຜູ້ເບິ່ງແຍງລະບົບໄດ້. ອຸປະກອນຂອງທ່ານຈະຖືກລຶບຂໍ້ມູນໃນຕອນນີ້.\n\nຫາກທ່ານມີຄຳຖາມ, ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບອົງກອນຂອງທ່ານ."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ການພິມຖືກປິດໄວ້ໂດຍ <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">ກຳລັງຈະຖ່າຍພາບໜ້າຈໍສຳລັບການລາຍງານຂໍ້ຜິດພາດໃນ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ.</item> <item quantity="one">ກຳລັງຈະຖ່າຍພາບໜ້າຈໍສຳລັບການລາຍງານຂໍ້ຜິດພາດໃນ <xliff:g id="NUMBER_0">%d</xliff:g> ວິນາທີ.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ໂໝດປິດສຽງ"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ປິດສຽງແລ້ວ"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ເປິດສຽງແລ້ວ"</string> @@ -1316,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"ເຊື່ອມຕໍ່ການດີບັກຜ່ານ USB ແລ້ວ"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"ແຕະເພື່ອປິດການດີບັກ USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"ເລືອກເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ເຊື່ອມຕໍ່ການດີບັກໄຮ້ສາຍແລ້ວ"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ແຕະເພື່ອປິດການດີບັກໄຮ້ສາຍ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ເລືອກປິດການປິດການນຳໃຊ້ການດີບັກໄຮ້ສາຍ."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ເປີດໃຊ້ໂໝດ Test Harness ແລ້ວ"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ດຳເນີນການຣີເຊັດເປັນຄ່າຈາກໂຮງງານເພື່ອປິດການນຳໃຊ້ໂໝດ Test Harness."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ເປີດນຳໃຊ້ຊີຣຽວຄອນໂຊແລ້ວ"</string> @@ -1842,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"ບໍ່ມີໝວດໝູ່"</string> <string name="importance_from_user" msgid="2782756722448800447">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string> <string name="importance_from_person" msgid="4235804979664465383">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ່ (ມີຜູ້ໃຊ້ທີ່ໃຊ້ບັນຊີນີ້ຢູ່ກ່ອນແລ້ວ) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ?"</string> <string name="language_selection_title" msgid="52674936078683285">"ເພີ່ມພາສາ"</string> @@ -2023,4 +2036,6 @@ <string name="resolver_no_apps_available" msgid="7710339903040989654">"ບໍ່ມີແອັບທີ່ສາມາດໃຊ້ໄດ້"</string> <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ພວກເຮົາບໍ່ພົບແອັບໃດໆເລີຍ"</string> <string name="resolver_switch_on_work" msgid="8294542702883688533">"ປຸ່ມເປີດຢູ່ວຽກ"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ບັນທຶກ ຫຼື ຫຼິ້ນສຽງໃນການໂທລະສັບ"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ອະນຸຍາດແອັບນີ້, ເມື່ອມອບໝາຍເປັນແອັບພລິເຄຊັນໂທລະສັບເລີ່ມຕົ້ນເພື່ອບັນທຶກ ຫຼື ຫຼິ້ນສຽງໃນການໂທລະສັບ."</string> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 2c7e96b189b1..e816f5e23969 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Šį įrenginį tvarko organizacija ir gali stebėti tinklo srautą. Palieskite, kad gautumėte daugiau informacijos."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Vietovės nustatymus pakeitė administratorius"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Palieskite, kad peržiūrėtumėte vietovės nustatymus."</string> + <string name="country_detector" msgid="7023275114706088854">"Šalies detektorius"</string> + <string name="location_service" msgid="2439187616018455546">"Vietovės paslauga"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Jutiklių pranešimų paslauga"</string> + <string name="twilight_service" msgid="8964898045693187224">"Paslauga „Twilight“"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratoriaus programos negalima naudoti. Dabar įrenginio duomenys bus ištrinti.\n\nJei turite klausimų, susisiekite su organizacijos administratoriumi."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Neleidžiama spausdinti (<xliff:g id="OWNER_APP">%s</xliff:g>)."</string> @@ -251,6 +255,10 @@ <item quantity="many">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundės.</item> <item quantity="other">Pranešimo apie riktą ekrano kopija bus užfiksuota po <xliff:g id="NUMBER_1">%d</xliff:g> sekundžių.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tylus režimas"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Garsas IŠJUNGTAS"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Garsas ĮJUNGTAS"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Bandykite dar kartą."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neužregistruota jokių kontrolinių kodų."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Jutiklis laikinai išjungtas."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nepavyko patvirtinti veido. Bandykite dar kartą."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nenustatėte Atrakinimo pagal veidą."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Atrakinimas pagal veidą šiame įrenginyje nepalaikomas."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Jutiklis laikinai išjungtas."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> veidas"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB derinimas prijungtas"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Palieskite, kad išjungtumėte USB derinimą"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Pasirinkite, kas išjungtumėte USB derinimą."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Belaidžio ryšio derinimas prijungtas"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Palieskite, kad išjungtumėte belaidžio ryšio derinimą"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Pasirinkite, kad išjungtumėte belaidžio ryšio derinimą."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Testavimo sistemos režimas įgalintas"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Atkurkite gamyklinius duomenis, kad išjungtumėte testavimo sistemos režimą."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serijos pultas įgalintas"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fone pradėtai priekinio plano paslaugai iš „<xliff:g id="PACKAGENAME">%1$s</xliff:g>“ nebus suteiktas leidimas naudojimo metu būsimose R versijose. Apsilankykite go/r-bg-fgs-restriction ir pateikite pranešimą apie riktą."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Padidinti garsą daugiau nei rekomenduojamas lygis?\n\nIlgai klausydami dideliu garsu galite pažeisti klausą."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Naudoti spartųjį pritaikymo neįgaliesiems klavišą?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kai spartusis klavišas įjungtas, paspaudus abu garsumo mygtukus ir palaikius 3 sekundes bus įjungta pritaikymo neįgaliesiems funkcija."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redaguoti sparčiuosius klavišus"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Atšaukti"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Išjungti spartųjį klavišą"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Be kategorijos"</string> <string name="importance_from_user" msgid="2782756722448800447">"Galite nustatyti šių pranešimų svarbą."</string> <string name="importance_from_person" msgid="4235804979664465383">"Tai svarbu dėl susijusių žmonių."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string> <string name="language_selection_title" msgid="52674936078683285">"Pridėkite kalbą"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Asmeninė"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Darbo"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Negalima bendrinti su darbo programomis"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Negalima bendrinti su asmeninėmis programomis"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT administratorius užblokavo bendrinimą tarp asmeninių programų ir darbo programų"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Įjunkite darbo programas"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Įjunkite darbo programas, kad galėtumėte pasiekti darbo programas ir kontaktus"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nėra pasiekiamų programų"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nepavyko rasti programų"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Įjungti darbo profilį"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefonų skambučių garso įrašo įrašymas arba leidimas"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Leidžiama šiai programai, esant prisijungus kaip numatytajai numerio rinkiklio programai, įrašyti ar leisti telefonų skambučių garso įrašą."</string> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 861421416f03..8aa7e5ae9b5f 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -195,6 +195,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Jūsu organizācija pārvalda šo ierīci un var uzraudzīt tīkla datplūsmu. Pieskarieties, lai saņemtu detalizētu informāciju."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Atrašanās vietas iestatījumus nomainīja administrators"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Pieskarieties, lai skatītu atrašanās vietas iestatījumus."</string> + <string name="country_detector" msgid="7023275114706088854">"Valsts noteikšanas rīks"</string> + <string name="location_service" msgid="2439187616018455546">"Atrašanās vietas pakalpojums"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensoru paziņojumu pakalpojums"</string> + <string name="twilight_service" msgid="8964898045693187224">"Krēslas noteikšanas pakalpojums"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratora lietotni nevar izmantot. Ierīcē saglabātie dati tiks dzēsti.\n\nJa jums ir kādi jautājumi, sazinieties ar savas organizācijas administratoru."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukāšanu atspējoja <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -248,6 +252,10 @@ <item quantity="one">Pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundes tiks veikts ekrānuzņēmums kļūdas pārskatam.</item> <item quantity="other">Pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm tiks veikts ekrānuzņēmums kļūdas pārskatam.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Klusuma režīms"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Skaņa ir IZSLĒGTA."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Skaņa ir IESLĒGTA."</string> @@ -549,8 +557,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Mēģiniet vēlreiz."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nav reģistrēts neviens pirksta nospiedums."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensors ir īslaicīgi atspējots."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +601,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nevar verificēt seju. Mēģiniet vēlreiz."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Autorizācija pēc sejas nav iestatīta."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Autorizācija pēc sejas šajā ierīcē netiek atbalstīta"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensors ir īslaicīgi atspējots."</string> <string name="face_name_template" msgid="3877037340223318119">"Seja <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1338,6 +1344,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB atkļūdošana ir pievienota."</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Pieskarieties, lai izslēgtu USB atkļūdošanu"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Atlasiet, lai atspējotu USB atkļūdošanu."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Aktivizēta bezvadu atkļūdošana"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Pieskarieties, lai izslēgtu bezvadu atkļūdošanu."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Atlasiet, lai atspējotu bezvadu atkļūdošanu."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Drošības pārbaudes režīms ir iespējots"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Lai atspējotu drošības pārbaudes režīmu, veiciet rūpnīcas datu atiestatīšanu."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Seriālā konsole ir iespējota"</string> @@ -1643,8 +1652,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fonā sāktam priekšplāna pakalpojumam no pakotnes <xliff:g id="PACKAGENAME">%1$s</xliff:g> nebūs atļaujas “while-in-use” turpmākajās R versijās. Lūdzu, skatiet vietni go/r-bg-fgs-restriction un iesniedziet kļūdas pārskatu."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vai palielināt skaļumu virs ieteicamā līmeņa?\n\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vai izmantot pieejamības saīsni?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad īsinājumtaustiņš ir ieslēgts, nospiežot abas skaļuma pogas un 3 sekundes turot tās, tiks aktivizēta pieejamības funkcija."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Rediģēt īsinājumtaustiņus"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Atcelt"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Izslēgt saīsni"</string> @@ -1877,6 +1885,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Nav kategorijas"</string> <string name="importance_from_user" msgid="2782756722448800447">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string> <string name="importance_from_person" msgid="4235804979664465383">"Tas ir svarīgi iesaistīto personu dēļ."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g> (lietotājs ar šādu kontu jau pastāv)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Pievienot valodu"</string> @@ -2052,20 +2062,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privātais profils"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Darba profils"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nevar kopīgot ar darba lietotnēm"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nevar kopīgot ar personīgajām lietotnēm"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Jūsu IT administrators bloķēja datu kopīgošanu starp personīgajām un darba lietotnēm."</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ieslēdziet darba lietotnes"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ieslēdziet darba lietotnes, lai piekļūtu darba lietotnēm un kontaktpersonām."</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nav pieejamu lietotņu"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Netika atrasta neviena lietotne."</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ieslēgt darba profilu"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Ierakstīt vai atskaņot audio tālruņa sarunās"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Ļauj šai lietotnei ierakstīt vai atskaņot audio tālruņa sarunās, kad tā ir iestatīta kā noklusējuma tālruņa lietojumprogramma."</string> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index a80779cfaca5..14979bd72f94 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Вашата организација управува со уредов и можно е да го следи сообраќајот на мрежата. Допрете за детали."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Администраторот ги променил поставките за локација"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Допрете за да ги видите поставките за локација."</string> + <string name="country_detector" msgid="7023275114706088854">"Детектор на земја"</string> + <string name="location_service" msgid="2439187616018455546">"Услуги според локација"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Услуга за известување од сензорот"</string> + <string name="twilight_service" msgid="8964898045693187224">"Услуга за самрак"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="one">Ќе се направи слика од екранот за извештајот за грешки за <xliff:g id="NUMBER_1">%d</xliff:g> секунда.</item> <item quantity="other">Ќе се направи слика од екранот за извештајот за грешки за <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Тивок режим"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Звукот е исклучен"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Звукот е вклучен"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Обидете се повторно."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Не се запишани отпечатоци."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорот е привремено оневозможен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ликот не може да се потврди. Обидете се повторно."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Не сте поставиле „Отклучување со лик“."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"„Отклучувањето со лик“ не е поддржано на уредов."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорот е привремено оневозможен."</string> <string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1167,7 +1173,7 @@ <string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> постојано запира"</string> <string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> постојано запира"</string> <string name="aerr_restart" msgid="2789618625210505419">"Отвори ја апликацијата повторно"</string> - <string name="aerr_report" msgid="3095644466849299308">"Испрати повратни информации"</string> + <string name="aerr_report" msgid="3095644466849299308">"Испратете повратни информации"</string> <string name="aerr_close" msgid="3398336821267021852">"Затвори"</string> <string name="aerr_mute" msgid="2304972923480211376">"Исклучи го звукот додека уредот не се рестартира"</string> <string name="aerr_wait" msgid="3198677780474548217">"Почекај"</string> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Поврзано е отстранување грешки преку USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Допрете за да го исклучите"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Изберете за да се оневозможи отстранување грешки на USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Безжичното отстранување грешки е поврзано"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Допрете за да се исклучи безжичното отстранување грешки"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Изберете за да се оневозможи безжично отстранување грешки."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Овозможен е режимот на рамка за тестирање"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Извршете фабричко ресетирање за да го оневозможите режимот на рамка за тестирање."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Сериската конзола е овозможена"</string> @@ -1623,8 +1632,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Услугата од преден план започната во заднина од <xliff:g id="PACKAGENAME">%1$s</xliff:g> нема да има дозола за „додека се користи“ во идните R-верзии. Погледнете на go/r-bg-fgs-restriction и испратете извештај за грешка."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Да го зголемиме звукот над препорачаното ниво?\n\nСлушањето звуци со голема јачина подолги периоди може да ви го оштети сетилото за слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Да се користи кратенка за „Пристапност“?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Кога е вклучена кратенката, ако ги притиснете двете копчиња за јачина на звук во времетраење од 3 секунди, ќе се стартува функција за пристапност."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Изменете ги кратенките"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Откажи"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Исклучи ја кратенката"</string> @@ -1847,6 +1855,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Некатегоризирано"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ја поставивте важноста на известувањава."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ова е важно заради луѓето кои се вклучени."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Веќе постои корисник со оваа сметка.)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Додај јазик"</string> @@ -2020,20 +2030,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Службени"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Не може да се споделува со работни апликации"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Не може да се споделува со лични апликации"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Вашиот администратор за ИТ го блокирал споделувањето помеѓу лични и работни апликации"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Вклучете работни апликации"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Вклучете работни апликации за да пристапувате до работни апликации и контакти"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Нема достапни апликации"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Не можевме да најдеме ниедна апликација"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Промени на работен"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Снимајте или пуштајте аудио во телефонски повици"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Дозволува апликацијава да снима или да пушта аудио во телефонски повици кога е назначена како стандардна апликација за бирање."</string> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index ccc6b314a082..1513db16adb7 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -191,10 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"വ്യക്തിപരമായ ഉപയോഗത്തിനായി, ഉപകരണത്തിന്റെ ഔദ്യോഗിക ഉപയോഗം അഡ്മിൻ അവസാനിപ്പിച്ചു"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"ഉപകരണം മാനേജുചെയ്യുന്നുണ്ട്"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"നിങ്ങളുടെ സ്ഥാപനമാണ് ഈ ഉപകരണം മാനേജുചെയ്യുന്നത്, നെറ്റ്വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കുകയും ചെയ്തേക്കാം, വിശദാംശങ്ങൾ അറിയാൻ ടാപ്പുചെയ്യുക."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> - <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> - <skip /> + <string name="location_changed_notification_title" msgid="4119726617105166830">"നിങ്ങളുടെ അഡ്മിൻ ലൊക്കേഷൻ ക്രമീകരണം മാറ്റി"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"നിങ്ങളുടെ ലൊക്കേഷൻ ക്രമീകരണം കാണാൻ ടാപ്പ് ചെയ്യുക."</string> + <string name="country_detector" msgid="7023275114706088854">"രാജ്യം കണ്ടെത്താനുള്ള സംവിധാനം"</string> + <string name="location_service" msgid="2439187616018455546">"ലൊക്കേഷൻ സേവനം"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"സെൻസർ അറിയിപ്പ് സേവനം"</string> + <string name="twilight_service" msgid="8964898045693187224">"സന്ധ്യാസമയത്തെ സേവനം"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്ക്കും"</string> <string name="factory_reset_message" msgid="2657049595153992213">"അഡ്മിൻ ആപ്പ് ഉപയോഗിക്കാനാകില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ മായ്ക്കപ്പെടും.\n\nനിങ്ങൾക്ക് ചോദ്യങ്ങൾ ഉണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ അഡ്മിനെ ബന്ധപ്പെടുക."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> പ്രിന്റിംഗ് പ്രവർത്തനരഹിതമാക്കി."</string> @@ -247,6 +249,10 @@ <item quantity="other">ബഗ് റിപ്പോർട്ടിനായി <xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിൽ സ്ക്രീൻഷോട്ട് എടുക്കുന്നു.</item> <item quantity="one">ബഗ് റിപ്പോർട്ടിനായി <xliff:g id="NUMBER_0">%d</xliff:g> സെക്കൻഡിൽ സ്ക്രീൻഷോട്ട് എടുക്കുന്നു.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"നിശബ്ദ മോഡ്"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ശബ്ദം ഓഫാണ്"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ശബ്ദം ഓണാണ്"</string> @@ -433,8 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"സിസ്റ്റം ക്യാമറ ഉപയോഗിച്ച് ഏത് സമയത്തും ചിത്രങ്ങളെടുക്കാനും വീഡിയോകൾ റെക്കോർഡ് ചെയ്യാനും ഈ വിശേഷാധികാര | സിസ്റ്റം ആപ്പിന് കഴിയും. ആപ്പിലും android.permission.CAMERA അനുമതി ഉണ്ടായിരിക്കണം"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"വൈബ്രേറ്റ് ചെയ്യൽ ആക്സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"ഫോൺ നമ്പറുകളിലേക്ക് നേരിട്ട് വിളിക്കുക"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ ഫോൺ നമ്പറുകളിലേക്ക് കോൾ ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് അപ്രതീക്ഷിത നിരക്കുകൾക്കോ കോളുകൾക്കോ ഇടയാക്കാം. ഇത് അടിയന്തര നമ്പറുകളിലേക്ക് വിളിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കില്ലെന്ന കാര്യം ശ്രദ്ധിക്കുക. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ കോളുകൾ ചെയ്യുന്നത് പണച്ചെലവിനിടയാക്കാം."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS കോൾ സേവനം ആക്സസ് ചെയ്യുക"</string> @@ -549,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"വീണ്ടും ശ്രമിക്കൂ."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"വിരലടയാളങ്ങൾ എൻറോൾ ചെയ്തിട്ടില്ല."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"കൈവിരൽ <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"മുഖം പരിശോധിക്കാൻ കഴിയില്ല. വീണ്ടും ശ്രമിക്കൂ."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് സജ്ജീകരിച്ചില്ല."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് ഈ ഉപകരണം പിന്തുണയ്ക്കുന്നില്ല."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string> <string name="face_name_template" msgid="3877037340223318119">"മുഖം <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1321,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ഡീബഗ്ഗിംഗ് കണക്റ്റ് ചെയ്തു"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ഡീബഗ്ഗുചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"പരിശോധനാ സംവിധാനങ്ങൾ മോഡ് പ്രവർത്തനക്ഷമമാക്കി"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"പരിശോധനാ സംവിധാന മോഡ് പ്രവർത്തനരഹിതമാക്കാൻ ഫാക്ടറി പുനഃക്രമീകരണം നിർവഹിക്കുക."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"സീരിയൽ കൺസോൾ പ്രവർത്തനക്ഷമമാക്കി"</string> @@ -1624,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> എന്നതിൽ നിന്നുള്ള പശ്ചാത്തലത്തിൽ ആരംഭിച്ച് ഫോർഗ്രൗണ്ടിൽ വരുന്ന സേവനത്തിന് ഭാവി R ബിൽഡുകളിൽ, \'ഉപയോഗിക്കുമ്പോൾ മാത്രമുള്ള അനുമതി\' ഉണ്ടായിരിക്കില്ല. go/r-bg-fgs-restriction കണ്ട് ബഗ് റിപ്പോർട്ട് ഫയൽ ചെയ്യുക."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"മുകളിൽക്കൊടുത്തിരിക്കുന്ന ശുപാർശചെയ്ത ലെവലിലേക്ക് വോളിയം വർദ്ധിപ്പിക്കണോ?\n\nഉയർന്ന വോളിയത്തിൽ ദീർഘനേരം കേൾക്കുന്നത് നിങ്ങളുടെ ശ്രവണ ശേഷിയെ ദോഷകരമായി ബാധിക്കാം."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ഉപയോഗസഹായി കുറുക്കുവഴി ഉപയോഗിക്കണോ?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"കുറുക്കുവഴി ഓണായിരിക്കുമ്പോൾ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"കുറുക്കുവഴികൾ തിരുത്തുക"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"റദ്ദാക്കുക"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"കുറുക്കുവഴി ഓഫാക്കുക"</string> @@ -1848,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"വർഗ്ഗീകരിച്ചിട്ടില്ലാത്ത"</string> <string name="importance_from_user" msgid="2782756722448800447">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string> <string name="importance_from_person" msgid="4235804979664465383">"ഉൾപ്പെട്ടിട്ടുള്ള ആളുകളെ കണക്കിലെടുക്കുമ്പോള് ഇത് പ്രധാനപ്പെട്ടതാണ്."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് (ഈ അക്കൗണ്ട് ഉപയോഗിക്കുന്ന ഒരു ഉപയോക്താവ് നിലവിലുണ്ട്) ഉപയോഗിച്ച് പുതിയ ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് ഉപയോഗിച്ച് പുതിയ ഉപയോക്താവിനെ സൃഷ്ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string> <string name="language_selection_title" msgid="52674936078683285">"ഒരു ഭാഷ ചേർക്കുക"</string> @@ -2021,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"വ്യക്തിപരമായത്"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ജോലിസ്ഥലം"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ഔദ്യോഗിക ആപ്പുകൾ ഉപയോഗിച്ച് പങ്കിടാനാവില്ല"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"വ്യക്തിപരമാക്കിയ ആപ്പുകൾ ഉപയോഗിച്ച് പങ്കിടാനാവില്ല"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"വ്യക്തിപരമാക്കിയ ആപ്പുകളുടെയും ഔദ്യോഗിക ആപ്പുകളുടെയും ഇടയിലുള്ള പങ്കിടൽ നിങ്ങളുടെ ഐടി അഡ്മിൻ ബ്ലോക്ക് ചെയ്തു"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ഔദ്യോഗിക ആപ്പുകൾ ഓണാക്കുക"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ഔദ്യോഗിക ആപ്പുകൾ, കോൺടാക്റ്റുകൾ എന്നിവ ആക്സസ് ചെയ്യാൻ ഔദ്യോഗിക ആപ്പുകൾ ഓണാക്കുക"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ആപ്പുകളൊന്നും ലഭ്യമല്ല"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ഞങ്ങൾക്ക് ആപ്പുകളൊന്നും കണ്ടെത്താൻ കഴിഞ്ഞില്ല"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"ഔദ്യോഗിക പ്രൊഫൈൽ ഓണാക്കുക"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ടെലിഫോൺ കോളുകൾ ചെയ്യുമ്പോൾ റെക്കോർഡ് ചെയ്യുക അല്ലെങ്കിൽ ഓഡിയോ പ്ലേ ചെയ്യുക"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ഡിഫോൾട്ട് ഡയലർ ആപ്പായി അസെെൻ ചെയ്യുന്ന സമയത്ത്, ടെലിഫോൺ കോളുകൾ ചെയ്യുമ്പോൾ റെക്കോർഡ് ചെയ്യാൻ അല്ലെങ്കിൽ ഓഡിയോ പ്ലേ ചെയ്യാൻ ഈ ആപ്പിനെ അനുവദിക്കുന്നു."</string> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index a21f6ecf3791..b61474de264c 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Таны байгууллага энэ төхөөрөмжийг удирдаж, сүлжээний ачааллыг хянадаг. Дэлгэрэнгүй мэдээлэл авах бол товшино уу."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Таны админ байршлын тохиргоог өөрчилсөн байна"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Байршлын тохиргоогоо харахын тулд товшино уу."</string> + <string name="country_detector" msgid="7023275114706088854">"Улс тодорхойлогч"</string> + <string name="location_service" msgid="2439187616018455546">"Байршлын үйлчилгээ"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Мэдрэгчийн мэдэгдлийн үйлчилгээ"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight үйлчилгээ"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string> <string name="factory_reset_message" msgid="2657049595153992213">"Админ аппыг ашиглах боломжгүй. Таны төхөөрөмжийг одоо устгана.\n\nХэрэв танд асуулт байгаа бол байгууллагынхаа админтай холбогдоно уу."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> хэвлэх үйлдлийг идэвхгүй болгосон."</string> @@ -245,6 +249,10 @@ <item quantity="other">Алдааны тайлангийн дэлгэцийн зургийг <xliff:g id="NUMBER_1">%d</xliff:g> секундад авна.</item> <item quantity="one">Алдааны тайлангийн дэлгэцийн зургийг <xliff:g id="NUMBER_0">%d</xliff:g> секундад авна.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Дуугүй горим"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Дуу хаагдсан"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Дуу асав"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Дахин оролдно уу."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бүртгүүлсэн хурууны хээ алга."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Хурууны хээ <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Царайг бататгаж чадсангүй. Дахин оролдоно уу."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Та царайгаар тайлахыг тохируулаагүй байна."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Царайгаар тайлахыг энэ төхөөрөмж дээр дэмждэггүй."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string> <string name="face_name_template" msgid="3877037340223318119">"Царай <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB дебаг холбогдсон"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB дебаг хийхийг унтраахын тулд товшино уу"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB дебаг хийхийг идэвхгүй болгох бол сонгоно уу."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Утасгүй дебагийг холболоо"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Утасгүй дебагийг унтраахын тулд товшино уу"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Утасгүй дебагийг идэвхгүй болгохын тулд сонгоно уу."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Туршилтын цогц горимыг идэвхжүүлсэн"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Туршилтын цогц горимыг идэвхгүй болгохын тулд үйлдвэрийн төлөвт шинэчилнэ үү."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Цуваа консолыг идэвхжүүлсэн"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>-н дэлгэц дээрх үйлчилгээг эхлүүлдэг дэвсгэр нь цаашид R хийцийн ашиглах үеийн зөвшөөрөлгүй болно. go/r-bg-fgs-restriction-г үзэж, алдааны мэдээ илгээнэ үү."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Хүртээмжийн товчлолыг ашиглах уу?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Товчлол асаалттай үед дууны түвшний хоёр товчлуурыг хамтад нь 3 секунд дарснаар хандалтын онцлогийг эхлүүлнэ."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Товчлолуудыг засах"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Болих"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Товчлолыг унтраах"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Ангилаагүй"</string> <string name="importance_from_user" msgid="2782756722448800447">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string> <string name="importance_from_person" msgid="4235804979664465383">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай (ийм бүртгэлтэй хэрэглэгч аль хэдийн байна) шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string> <string name="language_selection_title" msgid="52674936078683285">"Хэл нэмэх"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Хувийн"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Ажил"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ажлын аппуудтай хуваалцах боломжгүй"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Хувийн аппуудтай хуваалцах боломжгүй"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Танай IT админ хувийн болон ажлын аппуудын хооронд хуваалцахыг блоклосон."</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ажлын аппуудыг асаана уу"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ажлын апп, харилцагчдад хандахын тулд ажлын аппыг асаана уу"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Боломжтой апп алга байна"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Бид ямар ч апп олж чадсангүй"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ажил дээр сэлгэх"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Утасны дуудлагын үеэр аудио бичих эсвэл тоглуулах"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Энэ аппыг залгагч өгөгдмөл аппликэйшн болгосон үед түүнд утасны дуудлагын үеэр аудио бичих эсвэл тоглуулахыг зөвшөөрдөг."</string> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 5f392afe5262..d3c31a5839f1 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -193,6 +193,14 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"तुमची संस्था हे डिव्हाइस व्यवस्थापित करते आणि नेटवर्क रहदारीचे निरीक्षण करू शकते. तपशीलांसाठी टॅप करा."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"तुमच्या ॲडमिनने स्थान सेटिंग्ज बदलल्या आहेत"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"तुमची स्थान सेटिंग्ज पाहण्यासाठी टॅप करा."</string> + <!-- no translation found for country_detector (7023275114706088854) --> + <skip /> + <!-- no translation found for location_service (2439187616018455546) --> + <skip /> + <!-- no translation found for sensor_notification_service (7474531979178682676) --> + <skip /> + <!-- no translation found for twilight_service (8964898045693187224) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासक अॅप वापरता येणार नाही. तुमचे डिव्हाइस आता साफ केले जाईल.\n\nतुम्हाला कुठलेही प्रश्न असल्यास, तुमच्या संस्थेच्या प्रशासकाशी संपर्क साधा."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string> @@ -245,6 +253,10 @@ <item quantity="other">दोष अहवालासाठी <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये स्क्रीनशॉट घेत आहे.</item> <item quantity="one">दोष अहवालासाठी <xliff:g id="NUMBER_0">%d</xliff:g> सेकंदामध्ये स्क्रीनशॉट घेत आहे.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"मूक मोड"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ध्वनी बंद आहे"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ध्वनी चालू आहे"</string> @@ -546,8 +558,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"पुन्हा प्रयत्न करा."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोणत्याही फिंगरप्रिंटची नोंद झाली नाही"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"या डिव्हाइसमध्ये फिंगरप्रिंट सेन्सर नाही."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेन्सर तात्पुरता बंद केला आहे."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> बोट"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +602,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"चेहरा पडताळणी करू शकत नाही. पुन्हा प्रयत्न करा."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"तुम्ही फेस अनलॉक सेट केले नाही."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"या डिव्हाइसवर फेस अनलॉकला सपोर्ट नाही."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"सेन्सर तात्पुरता बंद केला आहे."</string> <string name="face_name_template" msgid="3877037340223318119">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1328,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB डीबगिंग कनेक्ट केले"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB डीबगिंग बंद करण्यासाठी टॅप करा"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB डीबगिंग बंद करण्यासाठी निवडा."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस डीबगिंग कनेक्ट केले आहे"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस डीबगिंग बंद करण्यासाठी टॅप करा"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस डीबगिंग बंद करण्यासाठी निवडा."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"टेस्ट हार्नेस मोड सुरू केला आहे"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"टेस्ट हार्नेस मोड बंद करण्यासाठी फॅक्टरी रीसेट करा."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"सिरीअल कन्सोल सुरू केला आहे"</string> @@ -1621,8 +1634,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> कडून बॅकग्राउंडने फोरग्राउंडमध्ये सुरू केलेल्या सेवेला भविष्यातील आर बिल्डमध्ये वापर करते वेळची परवानगी नसेल. कृपया go/r-bg-fgs-restriction पहा आणि बगची तक्रार नोंदवा."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"शिफारस केलेल्या पातळीच्या वर आवाज वाढवायचा?\n\nउच्च आवाजात दीर्घ काळ ऐकण्याने आपल्या श्रवणशक्तीची हानी होऊ शकते."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"प्रवेशयोग्यता शॉर्टकट वापरायचा?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट सुरू असताना, दोन्ही व्हॉल्यूम बटणे तीन सेकंदांसाठी दाबून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्य सुरू होईल."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"शॉर्टकट संपादित करा"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"रद्द करा"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"शॉर्टकट बंद करा"</string> @@ -1845,6 +1857,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"वर्गीकरण न केलेले"</string> <string name="importance_from_user" msgid="2782756722448800447">"तुम्ही या सूचनांचे महत्त्व सेट केले."</string> <string name="importance_from_person" msgid="4235804979664465383">"सामील असलेल्या लोकांमुळे हे महत्वाचे आहे."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची (हे खाते असलेला वापरकर्ता आधीपासून अस्तित्वात आहे) <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची आहे का?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची आहे का?"</string> <string name="language_selection_title" msgid="52674936078683285">"एक भाषा जोडा"</string> @@ -2018,20 +2032,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"वैयक्तिक"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ऑफिस"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ऑफिस ॲप्स सोबत शेअर करू शकत नाही"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"वैयक्तिक अॅप्स सोबत शेअर करू शकत नाही"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"तुमच्या आयटी ॲडमिनने वैयक्तिक आणि ऑफिस ॲप्स दरम्यान शेअर करणे ब्लॉक केले आहे"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ऑफिस अॅप्स सुरू करा"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ऑफिस ॲप्स & संपर्क अॅक्सेस करण्यासाठी ऑफिस ॲप्स सुरू करा"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"कोणतीही अॅप्स उपलब्ध नाहीत"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"आम्हाला कोणतीही अॅप्स सापडली नाहीत"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"ऑफिस प्रोफाइलवर स्विच करा"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"टेलिफोनी कॉलमध्ये ऑडिओ रेकॉर्ड करा किंवा प्ले करा"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"टेलिफोनी कॉलमध्ये ऑडिओ रेकॉर्ड करण्याची किंवा प्ले करण्यासाठी डीफॉल्ट डायलर अॅप्लिकेशन म्हणून असाइन केले असताना या ॲपला परवानगी देते."</string> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 848ebf48f233..909fcc9ed473 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi anda mengurus peranti ini dan mungkin memantau trafik rangkaian. Ketik untuk mendapatkan butiran."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Tetapan lokasi diubah oleh pentadbir anda"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Ketik untuk melihat tetapan lokasi anda."</string> + <string name="country_detector" msgid="7023275114706088854">"Pengesan Negara"</string> + <string name="location_service" msgid="2439187616018455546">"Perkhidmatan Lokasi"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Perkhidmatan Pemberitahuan Penderia"</string> + <string name="twilight_service" msgid="8964898045693187224">"Perkhidmatan Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Apl pentadbir tidak dapat digunakan. Peranti anda akan dipadamkan sekarang.\n\nJika anda ingin mengemukakan soalan, hubungi pentadbir organisasi anda."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Pencetakan dilumpuhkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Mengambil tangkapan skrin untuk laporan pepijat dalam masa <xliff:g id="NUMBER_1">%d</xliff:g> saat.</item> <item quantity="one">Mengambil tangkapan skrin untuk laporan pepijat dalam masa <xliff:g id="NUMBER_0">%d</xliff:g> saat.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mod senyap"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Bunyi DIMATIKAN"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Bunyi DIHIDUPKAN"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Cuba lagi."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tiada cap jari didaftarkan."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Penderia dilumpuhkan sementara."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Tidak dapat mengesahkan wajah. Cuba lagi."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Anda belum menyediakan wajah buka kunci."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Wajah buka kunci tidak disokong pada peranti ini."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Penderia dilumpuhkan sementara."</string> <string name="face_name_template" msgid="3877037340223318119">"Wajah <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Penyahpepijatan USB disambungkan"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Ketik untuk mematikan penyahpepijatan USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Pilih untuk melumpuhkan penyahpepijatan USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Penyahpepijatan wayarles disambungkan"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Ketik untuk mematikan penyahpepijatan wayarles"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Pilih untuk melumpuhkan penyahpepijatan wayarles."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Mod Abah-abah Ujian didayakan"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Laksanakan tetapan semula kilang untuk melumpuhkan Mod Abah-abah Ujian."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Konsol bersiri didayakan"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Perkhidmatan latar depan dimulakan latar belakang daripada <xliff:g id="PACKAGENAME">%1$s</xliff:g> tidak akan mempunyai kebenaran semasa-dalam-penggunaan dalam binaan R akan datang. Sila lihat go/r-bg-fgs-restriction dan failkan laporan pepijat."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Naikkan kelantangan melebihi paras yang disyokorkan?\n\nMendengar pada kelantangan yang tinggi untuk tempoh yang lama boleh merosakkan pendengaran anda."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Kebolehaksesan?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Batal"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Matikan pintasan"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Tidak dikategorikan"</string> <string name="importance_from_user" msgid="2782756722448800447">"Anda menetapkan kepentingan pemberitahuan ini."</string> <string name="importance_from_person" msgid="4235804979664465383">"Mesej ini penting disebabkan orang yang terlibat."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akaun ini sudah wujud) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Tambahkan bahasa"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Peribadi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Tidak dapat berkongsi dengan apl kerja"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Tidak dapat berkongsi dengan apl peribadi"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Pentadbir IT anda menyekat perkongsian antara apl peribadi dan kerja"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Hidupkan apl kerja"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Hidupkan apl kerja untuk mengakses apl & kenalan kerja"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Tiada rangkaian yang tersedia"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Kami tidak menemukan sebarang apl"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Hidupkan kerja"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Rakam atau mainkan audio dalam panggilan telefoni"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Apabila ditetapkan sebagai apl pendail lalai, membenarkan apl ini merakam atau memainkan audio dalam panggilan telefoni."</string> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 95a41f22f84e..9a902c8db193 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ဤစက်ပစ္စည်းကို သင်၏ အဖွဲ့အစည်းက စီမံပြီး ကွန်ရက်အသွားအလာကို စောင့်ကြည့်နိုင်ပါသည်။ ထပ်မံလေ့လာရန် တို့ပါ။"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"သင့်စီမံခန့်ခွဲသူက တည်နေရာပြ ဆက်တင်များကို ပြောင်းထားသည်"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"သင့်တည်နေရာပြ ဆက်တင်များကို ကြည့်ရန် တို့ပါ။"</string> + <string name="country_detector" msgid="7023275114706088854">"နိုင်ငံ ရှာဖွေစနစ်"</string> + <string name="location_service" msgid="2439187616018455546">"တည်နေရာဝန်ဆောင်မှု"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"အာရုံခံကိရိယာ အကြောင်းကြားချက် ဝန်ဆောင်မှု"</string> + <string name="twilight_service" msgid="8964898045693187224">"နေဝင်ဆည်းဆာ ဝန်ဆောင်မှု"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string> <string name="factory_reset_message" msgid="2657049595153992213">"စီမံခန့်ခွဲမှု အက်ပ်ကို သုံး၍မရပါ။ သင်၏ စက်ပစ္စည်းအတွင်းရှိ အရာများကို ဖျက်လိုက်ပါမည်\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> က ပုံနှိပ်ထုတ်ယူခြင်းကို ပိတ်ထားသည်။"</string> @@ -245,6 +249,10 @@ <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အတွင်း ချွတ်ယွင်းချက် အစီရင်ခံရန်အတွက် မျက်နှာပြင်ဓာတ်ပုံ ရိုက်ပါမည်။</item> <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> စက္ကန့်အတွင်း ချွတ်ယွင်းချက် အစီရင်ခံရန်အတွက် မျက်နှာပြင်ဓာတ်ပုံ ရိုက်ပါမည်။</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"အသံတိတ်စနစ်"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"အသံပိတ်ထားသည်"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"အသံဖွင့်ထားသည်"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ပြန်ကြိုးစားပါ"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"မည်သည့် လက်ဗွေကိုမျှ ထည့်သွင်းမထားပါ။"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"မျက်နှာကို အတည်ပြု၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို ထည့်သွင်းမထားပါ"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"ဤစက်ပစ္စည်းတွင် မျက်နှာမှတ် သော့ဖွင့်ခြင်းကို သုံး၍မရပါ။"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string> <string name="face_name_template" msgid="3877037340223318119">"မျက်နှာ <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1239,7 +1245,7 @@ <string name="volume_icon_description_notification" msgid="579091344110747279">"အကြောင်းကြားသံအတိုးအကျယ်"</string> <string name="ringtone_default" msgid="9118299121288174597">"မူရင်းမြည်သံ"</string> <string name="ringtone_default_with_actual" msgid="2709686194556159773">"မူရင်း (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> - <string name="ringtone_silent" msgid="397111123930141876">"တစ်ခုမှမဟုတ်"</string> + <string name="ringtone_silent" msgid="397111123930141876">"တစ်ခုမျှမဟုတ်"</string> <string name="ringtone_picker_title" msgid="667342618626068253">"မြည်သံများ"</string> <string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"နှိုးစက်သံ"</string> <string name="ringtone_picker_title_notification" msgid="6387191794719608122">"အကြောင်းကြားချက်အသံ"</string> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB အမှားရှာပြင်စနစ် ချိတ်ဆက်ထားသည်"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB အမှားရှာပြင်ခြင်းကို ပိတ်ရန် တို့ပါ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ဖြင့် အမှားရှာပြင်ခြင်းကို ပိတ်ရန် ရွေးပါ။"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ကြိုးမဲ့ အမှားရှာပြင်ခြင်းကို ချိတ်ဆက်ပြီးပြီ"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ကြိုးမဲ့ အမှားရှာပြင်ခြင်းကို ပိတ်ရန် တို့ပါ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ကြိုးမဲ့ အမှားရှာပြင်ခြင်းကို ပိတ်ရန် ရွေးပါ။"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"\'စမ်းသပ်ခြင်းစနစ်မုဒ်\' ဖွင့်ထားသည်"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"\'စမ်းသပ်ခြင်းစနစ် မုဒ်\' ကိုပိတ်ရန် စက်ရုံထုတ်အတိုင်း ပြင်ဆင်သတ်မှတ်ပါ။"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"အမှတ်စဉ် ကွန်ဆိုးလ်ကို ဖွင့်ထားသည်"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> တွင် မှ စတင်သည့် foreground ဝန်ဆောင်မှုသည် နောက်ထွက်ရှိမည့် R စုပေါင်းစပ်ပေါင်း ပရိုဂရမ်များတွင် အသုံးပြုစဉ်အတွင်း ခွင့်ပြုချက် ရရှိမည်မဟုတ်ပါ။ go/r-bg-fgs-ကန့်သတ်ချက်များကို ကြည့်ပြီး အမှားသတင်းပို့ချက်တစ်ခု တင်သွင်းပါ။"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"အသံကို အကြံပြုထားသည့် ပမာဏထက် မြှင့်ပေးရမလား?\n\nအသံကို မြင့်သည့် အဆင့်မှာ ကြာရှည်စွာ နားထောင်ခြင်းက သင်၏ နားကို ထိခိုက်စေနိုင်သည်။"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ်ကို အသုံးပြုလိုပါသလား။"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံထိန်းခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ဖြတ်လမ်းများကို တည်းဖြတ်ရန်"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"မလုပ်တော့"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ဖြတ်လမ်းလင့်ခ်ကို ပိတ်ရန်"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"အမျိုးအစားမခွဲရသေးပါ"</string> <string name="importance_from_user" msgid="2782756722448800447">"ဤသတိပေးချက်များ၏ အရေးပါမှုကိုသတ်မှတ်ပြီးပါပြီ။"</string> <string name="importance_from_person" msgid="4235804979664465383">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား (ဤအကောင့်ဖြင့် အသုံးပြုသူ ရှိနှင့်ပြီးဖြစ်သည်) ။"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား ။"</string> <string name="language_selection_title" msgid="52674936078683285">"ဘာသာစကားတစ်ခု ထည့်ပါ"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ကိုယ်ပိုင်"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"အလုပ်"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"အလုပ်သုံးအက်ပ်များနှင့် မျှဝေ၍ မရပါ"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ကိုယ်ပိုင်သုံးအက်ပ်များနှင့် မျှဝေ၍ မရပါ"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"သင့်အိုင်တီ စီမံခန့်ခွဲသူက ကိုယ်ပိုင်သုံးနှင့် အလုပ်သုံးအက်ပ်များအကြား မျှဝေခြင်းကို ပိတ်ထားသည်"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"အလုပ်သုံးအက်ပ်များကို ဖွင့်ပါ"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"အလုပ်သုံးအက်ပ်နှင့် အဆက်အသွယ်များကို သုံးရန် အလုပ်သုံးအက်ပ်များကို ဖွင့်ပါ"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"မည်သည့်အက်ပ်မျှ မရှိပါ"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"မည်သည့်အက်ပ်ကိုမျှ မတွေ့ပါ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"အလုပ်သုံးအနေအထားကို ဖွင့်ပါ"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ဖုန်းခေါ်ဆိုမှုများအတွင်း အသံဖမ်းခြင်း သို့မဟုတ် ဖွင့်ခြင်း"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ဤအက်ပ်အား မူလ dialer အပလီကေးရှင်းအဖြစ် သတ်မှတ်ထားစဉ် ဖုန်းခေါ်ဆိုမှုများအတွင်း အသံဖမ်းခြင်း သို့မဟုတ် ဖွင့်ခြင်း ပြုလုပ်ရန် ခွင့်ပြုပါ။"</string> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 7145ef3da91a..93afcb204cf2 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasjonen din kontrollerer denne enheten og kan overvåke nettverkstrafikk. Trykk for å få mer informasjon."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Posisjonsinnstillingene er endret av administratoren din"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Trykk for å se posisjonsinnstillingene dine."</string> + <string name="country_detector" msgid="7023275114706088854">"Landsoppdagelse"</string> + <string name="location_service" msgid="2439187616018455546">"Posisjonstjeneste"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administratorappen kan ikke brukes. Enheten din blir nå tømt.\n\nTa kontakt med administratoren for organisasjonen din hvis du har spørsmål."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> har slått av utskrift."</string> @@ -245,6 +249,10 @@ <item quantity="other">Tar skjermdump for feilrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item> <item quantity="one">Tar skjermdump for feilrapporten om <xliff:g id="NUMBER_0">%d</xliff:g> sekund.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Stillemodus"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Lyden er av"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Lyden er på"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Prøv igjen."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ingen fingeravtrykk er registrert."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidig slått av."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Kan ikke bekrefte ansiktet. Prøv igjen."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Du har ikke konfigurert Ansiktslås."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås støttes ikke på denne enheten"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidig slått av."</string> <string name="face_name_template" msgid="3877037340223318119">"Ansikt <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-feilsøking tilkoblet"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Trykk for å slå av USB-feilsøking"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Velg for å deaktivere USB-debugging."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Trådløs feilsøking er koblet til"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Trykk for å slå av trådløs feilsøking"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Velg for å slå av trådløs feilsøking."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Testrammeverk-modus er slått på"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Tilbakestill enheten til fabrikkstandard for å slå av Testrammeverk-modus."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Seriekonsollen er aktivert"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Forgrunnstjenesten fra <xliff:g id="PACKAGENAME">%1$s</xliff:g>, som ble startet i bakgrunnen, kommer ikke til å ha tillatelser mens den er i bruk i fremtidige R-delversjoner. Les go/r-bg-fgs-restriction og send inn en feilrapport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du øke volumet til over anbefalt nivå?\n\nHvis du hører på et høyt volum over lengre perioder, kan det skade hørselen din."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruke tilgjengelighetssnarveien?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Endre snarveier"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Avbryt"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Slå av snarveien"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Uten kategori"</string> <string name="importance_from_user" msgid="2782756722448800447">"Du angir viktigheten for disse varslene."</string> <string name="importance_from_person" msgid="4235804979664465383">"Dette er viktig på grunn av folkene som er involvert."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g> (en bruker med denne kontoen eksisterer allerede)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Legg til et språk"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Kan ikke dele med jobbapper"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kan ikke dele med personlige apper"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT-administratoren din har blokkert deling mellom personlige apper og jobbapper"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Slå på jobbapper"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Slå på jobbapper for å få tilgang til jobbapper og kontakter"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Ingen apper er tilgjengelige"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Vi fant ingen apper"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Slå på jobbprofilen"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Ta opp eller spill av lyd i telefonsamtaler"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tillater at denne appen tar opp eller spiller av lyd i telefonsamtaler når den er angitt som standard ringeapp."</string> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 6a61636844ec..d47a8ed50e0d 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"तपाईंको संगठनले यस यन्त्रको व्यवस्थापन गर्दछ र नेटवर्क ट्राफिकको अनुगमन गर्न सक्छ। विवरणहरूका लागि ट्याप गर्नुहोस्।"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"तपाईंका प्रशासकले परिवर्तन गरेका स्थानसम्बन्धी सेटिङहरू"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"आफ्नो स्थानका सेटिङहरू हेर्न ट्याप गर्नुहोस्।"</string> + <string name="country_detector" msgid="7023275114706088854">"देश पत्ता लगाउने सुविधा"</string> + <string name="location_service" msgid="2439187616018455546">"स्थानसम्बन्धी सेवा"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"सेन्सरको सूचनासम्बन्धी सेवा"</string> + <string name="twilight_service" msgid="8964898045693187224">"ट्वाइलाइट सेवा"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"प्रशासकको अनुप्रयोग प्रयोग गर्न मिल्दैन। तपाईंको यन्त्रको डेटा अब मेटाइने छ।\n\nतपाईंसँग प्रश्नहरू भएका खण्डमा आफ्नो संगठनका प्रशासकसँग सम्पर्क गर्नुहोस्।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ले छाप्ने कार्यलाई असक्षम पार्यो।"</string> @@ -245,6 +249,10 @@ <item quantity="other"> बग रिपोर्टको लागि <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा स्क्रिसट लिँदै।</item> <item quantity="one"> बग रिपोर्टको लागि <xliff:g id="NUMBER_0">%d</xliff:g> सेकेन्डमा स्क्रिसट लिँदै।</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"मौन मोड"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"आवाज बन्द छ"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ध्वनि खुल्ला छ"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"पुन: प्रयास गर्नुहोला।"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कुनै पनि फिंगरप्रिन्ट दर्ता गरिएको छैन।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो यन्त्रमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"केही समयका लागि सेन्सर असक्षम पारियो।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"औंला <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"अनुहार पुष्टि गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"तपाईंले फेस अनलक सुविधा सेट अप गर्नुभएको छैन।"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"यस यन्त्रमा फेस अनलक सुविधा प्रयोग गर्न मिल्दैन।"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"केही समयका लागि सेन्सर असक्षम पारियो।"</string> <string name="face_name_template" msgid="3877037340223318119">"अनुहार <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1324,6 +1330,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB डिबग गर्ने सुविधा सुचारू छ"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB डिबग प्रक्रिया निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB डिबगिङलाई असक्षम पार्न ट्याप गर्नुहोस्।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस डिबग प्रक्रिया जडान गरियो"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस डिबग प्रक्रिया निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस डिबग प्रक्रिया असक्षम पार्ने विकल्प चयन गर्नुहोस्।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"परीक्षण प्याकेज मोड सक्षम पारियो"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"परीक्षण प्याकेज मोड असक्षम पार्न फ्याक्ट्री रिसेट गर्नुहोस्।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"क्रमसम्बन्धी कन्सोल सक्षम पारियो"</string> @@ -1627,8 +1636,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> को पृष्ठभूमिबाट सुरु गरिने अग्रभूमि सेवाका भविष्यमा आउने R बिल्डहरूमा चलाउँदै गर्दा प्रयोग गर्ने अनुमतिको दिइने छैन। कृपया go/r-bg-fgs-restriction हेर्नुहोस् र कुनै बगसम्बन्धी रिपोर्ट फाइल गर्नुहोस्।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"सिफारिस तहभन्दा आवाज ठुलो गर्नुहुन्छ?\n\nलामो समय सम्म उच्च आवाजमा सुन्दा तपाईँको सुन्ने शक्तिलाई हानी गर्न सक्छ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"पहुँच सम्बन्धी सर्टकट प्रयोग गर्ने हो?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"यो सर्टकट सक्रिय हुँदा, ३ सेकेन्डसम्म दुवै भोल्युम बटन थिच्नुले पहुँचसम्बन्धी कुनै सुविधा सुरु गर्ने छ।"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"सर्टकटहरू सम्पादन गर्नुहोस्"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"रद्द गर्नुहोस्"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"सर्टकटलाई निष्क्रिय पार्नुहोस्"</string> @@ -1851,6 +1859,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"वर्गीकरण नगरिएको"</string> <string name="importance_from_user" msgid="2782756722448800447">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहोस् ।"</string> <string name="importance_from_person" msgid="4235804979664465383">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (यस खाताको प्रयोगकर्ता पहिले नै अवस्थित छ) मा नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> मा नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string> <string name="language_selection_title" msgid="52674936078683285">"भाषा थप्नुहोस्"</string> @@ -2024,20 +2034,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"व्यक्तिगत"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"काम"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"कामसम्बन्धी अनुप्रयोगहरूसँग आदान प्रदान गर्न सकिँदैन"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"व्यक्तिगत अनुप्रयोगहरूसँग आदान प्रदान गर्न सकिँदैन"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"तपाईंका IT प्रशासकले व्यक्तिगत र कामसम्बन्धी अनुप्रयोगहरूबिच आदान प्रदान गर्ने सुविधामाथि रोक लगाउनुभयो"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"कामसम्बन्धी अनुप्रयोगहरू सक्रिय गर्नुहोस्"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"कामसम्बन्धी अनुप्रयोग र सम्पर्क ठेगानाहरूमाथि पहुँच राख्न कामसम्बन्धी अनुप्रयोगहरू सक्रिय गर्नुहोस्"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"कुनै पनि अनुप्रयोग उपलब्ध छैन"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"हामीले कुनै पनि अनुप्रयोग फेला पार्न सकेनौँ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"कार्य प्रोफाइल सक्षम पार्नुहोस्"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"टेलिफोन कल गर्दै गर्दा अडियो रेकर्ड गर्नुहोस् वा प्ले गर्नुहोस्"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"यस अनुप्रयोगलाई पूर्वनिर्धारित डायलर अनुप्रयोग निर्धारण गर्दा टेलिफोन कलको अडियो रेकर्ड गर्ने र प्ले गर्ने अनुमति दिन्छ।"</string> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index e959a0734d2b..df2f96300baf 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Dit apparaat wordt beheerd door je organisatie. Het netwerkverkeer kan worden bijgehouden. Tik voor meer informatie."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Locatie-instellingen gewijzigd door je beheerder"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tik om je locatie-instellingen te bekijken."</string> + <string name="country_detector" msgid="7023275114706088854">"Landdetectie"</string> + <string name="location_service" msgid="2439187616018455546">"Locatieservice"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Service voor sensormeldingen"</string> + <string name="twilight_service" msgid="8964898045693187224">"Service voor schemering"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string> <string name="factory_reset_message" msgid="2657049595153992213">"De beheer-app kan niet worden gebruikt. Je apparaat wordt nu gewist.\n\nNeem contact op met de beheerder van je organisatie als je vragen hebt."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Afdrukken uitgeschakeld door <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Er wordt over <xliff:g id="NUMBER_1">%d</xliff:g> seconden een screenshot gemaakt voor het bugrapport.</item> <item quantity="one">Er wordt over <xliff:g id="NUMBER_0">%d</xliff:g> seconde een screenshot gemaakt voor het bugrapport.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Stille modus"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Geluid is UIT"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Geluid is AAN"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Probeer het opnieuw."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukken geregistreerd."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor tijdelijk uitgeschakeld."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Kan gezicht niet verifiëren. Probeer het nog eens."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Je hebt ontgrendelen via gezichtsherkenning niet ingesteld."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ontgrendelen via gezichtsherkenning wordt niet ondersteund op dit apparaat."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor tijdelijk uitgeschakeld."</string> <string name="face_name_template" msgid="3877037340223318119">"Gezicht <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-foutopsporing verbonden"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tik om USB-foutopsporing uit te schakelen"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecteer deze optie om USB-foutopsporing uit te schakelen."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Draadloze foutopsporing verbonden"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tik om draadloze foutopsporing uit te schakelen"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecteer deze optie om draadloze foutopsporing uit te schakelen."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test harness-modus is ingeschakeld"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Reset de fabrieksinstellingen om de test harness-modus uit te schakelen."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Seriële console ingeschakeld"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"De op de achtergrond gestarte voorgrondservice van <xliff:g id="PACKAGENAME">%1$s</xliff:g> heeft geen rechten tijdens gebruik in toekomstige R-builds. Ga naar go/r-bg-fgs-restriction en dien een bugrapport in."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Snelkoppeling toegankelijkheid gebruiken?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Als de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Snelkoppelingen bewerken"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Annuleren"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Sneltoets uitschakelen"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Geen categorie"</string> <string name="importance_from_user" msgid="2782756722448800447">"Je stelt het belang van deze meldingen in."</string> <string name="importance_from_person" msgid="4235804979664465383">"Dit is belangrijk vanwege de betrokken mensen."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt (er is al een gebruiker met dit account)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string> <string name="language_selection_title" msgid="52674936078683285">"Een taal toevoegen"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlijk"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Kan niet delen met werk-apps"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kan niet delen met persoonlijke apps"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Je IT-beheerder heeft delen tussen persoonlijke en werk-apps geblokkeerd"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Schakel werk-apps in"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Schakel werk-apps in om toegang tot werk-apps en -contacten te krijgen"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Geen apps beschikbaar"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"We kunnen geen apps vinden"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Werkprofiel inschakelen"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Audio opnemen of afspelen in telefoongesprekken"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Hiermee mag deze app (indien toegewezen als standaard dialer-app) audio opnemen of afspelen in telefoongesprekken."</string> </resources> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 53b231cc167f..cc5aa2811e65 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ଆପଣଙ୍କ ସଂସ୍ଥା ଏହି ଡିଭାଇସକୁ ପରିଚାଳନା କରନ୍ତି ଏବଂ ନେଟୱର୍କ ଟ୍ରାଫିକ୍ ନୀରିକ୍ଷଣ କରନ୍ତି। ବିବରଣୀ ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"ଲୋକେସନ୍ ସେଟିଂସ୍ ଆପଣଙ୍କର ଆଡମିନଙ୍କ ଦ୍ୱରା ବଦଳାଯାଇଛି"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"ଆପଣଙ୍କର ଲୋକେସନ୍ ସେଟିଂସ୍ ଦେଖିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string> + <string name="country_detector" msgid="7023275114706088854">"କଣ୍ଟ୍ରି ଡିଟେକ୍ଟର୍"</string> + <string name="location_service" msgid="2439187616018455546">"ଲୋକେସନ୍ ସର୍ଭିସ୍"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"ସେନ୍ସର୍ ନୋଟିଫିକେସନ୍ ସର୍ଭିସ୍"</string> + <string name="twilight_service" msgid="8964898045693187224">"ଟ୍ୱିଲାଇଟ୍ ସର୍ଭିସ୍"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ଆଡମିନ୍ ଆପ୍ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଲିଭାଇଦିଆଯିବ। \n\nଯଦି ଆପଣଙ୍କର କୌଣସି ପ୍ରଶ୍ନ ରହିଥାଏ, ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରିଣ୍ଟିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string> @@ -245,6 +249,10 @@ <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> ସେକେଣ୍ଡରେ ବଗ୍ ରିପୋର୍ଟ ପାଇଁ ସ୍କ୍ରୀନଶଟ୍ ନେଉଛି।</item> <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> ସେକେଣ୍ଡରେ ବଗ୍ ରିପୋର୍ଟ ପାଇଁ ସ୍କ୍ରୀନଶଟ୍ ନେଉଛି।</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ସାଇଲେଣ୍ଟ ମୋଡ୍"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ସାଉଣ୍ଡ ଅଫ୍ ଅଛି"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ସାଉଣ୍ଡ ଅନ୍ ଅଛି"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"କୌଣସି ଆଙ୍ଗୁଠି ଚିହ୍ନ ପଞ୍ଜୀକୃତ ହୋଇନାହିଁ।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍ରେ ଟିପଚିହ୍ନ ସେନ୍ସର୍ ନାହିଁ।"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ଆଙ୍ଗୁଠି <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"ମୁହଁ ଚିହ୍ନଟ କରିପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"ଆପଣ ଫେସ୍ ଅନ୍ଲକ୍ ସେଟ୍ ଅପ୍ କରିନାହାଁନ୍ତି"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"ଏହି ଡିଭାଇସ୍ରେ ଫେସ୍ ଅନ୍ଲକ୍ ସମର୍ଥିତ ନୁହେଁ।"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g>ଙ୍କ ଫେସ୍"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ଡିବଗିଙ୍ଗ ସଂଯୁକ୍ତ ହୋଇଛି"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USBର ଡିବଗିଙ୍ଗ ସୁବିଧାକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ଡିବଗିଙ୍ଗକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ୱେୟାରଲେସ୍ ଡିବଗିଂ ସଂଯୋଗ କରାଯାଇଛି"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ୱାୟାରଲେସର ଡିବଗିଂକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ୱାୟାରଲେସ୍ ଡିବଗିଂକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ଟେଷ୍ଟ ହାର୍ନେସ୍ ମୋଡ୍ ସକ୍ଷମ ଅଛି"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ଟେଷ୍ଟ ହାର୍ନେସ୍ ମୋଡ୍ ଅକ୍ଷମ କରିବାକୁ ଏକ ଫ୍ୟାକ୍ଟରୀ ରିସେଟ୍ କରନ୍ତୁ।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"କ୍ରମିକ କନ୍ସୋଲ୍କୁ ସକ୍ଷମ କରାଯାଇଛି"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ପୃଷ୍ଠଭୂମିରେ <xliff:g id="PACKAGENAME">%1$s</xliff:g>ରୁ ଆରମ୍ଭ ହୋଇଥିବା ସମ୍ମୁଖଭାଗ ସେବା ପାଇଁ ଭବିଷ୍ୟତର R ବିଲ୍ଡଗୁଡ଼ିକରେ ବ୍ୟବହାର କରାଯିବା ସମୟରେ ଅନୁମତି ସୁବିଧା ରହିବ ନାହିଁ। ଦୟାକରି go/r-bg-fgs-restriction ଦେଖନ୍ତୁ ଏବଂ ଏକ ବଗରିପୋର୍ଟ ଫାଇଲ୍ କରନ୍ତୁ।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ମାତ୍ରା ବଢ଼ାଇ ସୁପାରିଶ ସ୍ତର ବଢ଼ାଉଛନ୍ତି? \n\n ଲମ୍ବା ସମୟ ପର୍ଯ୍ୟନ୍ତ ଉଚ୍ଚ ଶବ୍ଦରେ ଶୁଣିଲେ ଆପଣଙ୍କ ଶ୍ରବଣ ଶକ୍ତି ଖରାପ ହୋଇପାରେ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ଆକ୍ସେସବିଲିଟି ଶର୍ଟକଟ୍ ବ୍ୟବହାର କରିବେ?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ସର୍ଟକଟ୍ ଚାଲୁ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଏକ ଆକ୍ସେସବିଲିଟି ଫିଚର୍ ଆରମ୍ଭ ହେବ।"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ସର୍ଟକଟଗୁଡ଼ିକୁ ସମ୍ପାଦନ କରନ୍ତୁ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ବାତିଲ୍ କରନ୍ତୁ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ଶର୍ଟକଟ୍ ବନ୍ଦ କରନ୍ତୁ"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"ଅବର୍ଗୀକୃତ"</string> <string name="importance_from_user" msgid="2782756722448800447">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ପ୍ରମୁଖତା ଆପଣ ସେଟ୍ କରନ୍ତି।"</string> <string name="importance_from_person" msgid="4235804979664465383">"ସମ୍ପୃକ୍ତ ଲୋକଙ୍କ କାରଣରୁ ଏହା ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଅଟେ।"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ (ପୂର୍ବରୁ ଏହି ଆକାଉଣ୍ଟ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ନାମରେ ଅଛି) ଅନୁମତି ଦେବେ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string> <string name="language_selection_title" msgid="52674936078683285">"ଏକ ଭାଷା ଯୋଡ଼ନ୍ତୁ"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ବ୍ୟକ୍ତିଗତ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"କାର୍ଯ୍ୟ"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ସହ ସେୟାର୍ କରିପାରିବ ନାହିଁ"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ବ୍ୟକ୍ତିଗତ ଆପଗୁଡ଼ିକ ସହ ସେୟାର୍ କରିପାରିବ ନାହିଁ"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ଆପଣଙ୍କର IT ଆଡମିନ୍ ବ୍ୟକ୍ତିଗତ ଏବଂ କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ମଧ୍ୟରେ ସେୟାରିଂ ବ୍ଲକ୍ କରିଛନ୍ତି"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକୁ ଚାଲୁ କରନ୍ତୁ"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପ୍ ଏବଂ ଯୋଗାଯୋଗଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ କରିବା ପାଇଁ କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକୁ ଚାଲୁ କରନ୍ତୁ"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"କୌଣସି ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ଆମେ କୌଣସି ଆପ୍ ପାଇଲୁ ନାହିଁ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"କାର୍ଯ୍ୟସ୍ଥଳୀ ପ୍ରୋଫାଇଲରେ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ଟେଲିଫୋନି କଲଗୁଡ଼ିକରେ ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ ବା ଚଲାନ୍ତୁ"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ଏହି ଆପ୍ ଡିଫଲ୍ଟ ଡାଏଲର୍ ଆପ୍ଲିକେସନ୍ ଭାବରେ ଆସାଇନ୍ ହୋଇଥିଲେ ଟେଲିଫୋନି କଲଗୁଡ଼ିକରେ ଅଡିଓ ରେକର୍ଡ କରିବା ବା ଚଲାଇବା ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index b5194eb7ba1b..6c8b5c3e3ef4 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -193,6 +193,14 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ਤੁਹਾਡਾ ਸੰਗਠਨ ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਦਾ ਹੈ ਅਤੇ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਟਿਕਾਣਾ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲ ਦਿੱਤਾ ਹੈ"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"ਆਪਣੀਆਂ ਟਿਕਾਣਾ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> + <!-- no translation found for country_detector (7023275114706088854) --> + <skip /> + <!-- no translation found for location_service (2439187616018455546) --> + <skip /> + <!-- no translation found for sensor_notification_service (7474531979178682676) --> + <skip /> + <!-- no translation found for twilight_service (8964898045693187224) --> + <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> @@ -245,6 +253,10 @@ <item quantity="one">ਬੱਗ ਰਿਪੋਰਟ ਲਈ <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਿਆ ਜਾ ਰਿਹਾ ਹੈ।</item> <item quantity="other">ਬੱਗ ਰਿਪੋਰਟ ਲਈ <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲਿਆ ਜਾ ਰਿਹਾ ਹੈ।</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"ਸਾਈਲੈਂਟ ਮੋਡ"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ਅਵਾਜ਼ ਬੰਦ ਹੈ"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ਅਵਾਜ਼ ਚਾਲੂ ਹੈ"</string> @@ -546,8 +558,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ਕੋਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਰਜ ਨਹੀਂ ਕੀਤੇ ਗਏ।"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨਹੀਂ ਹੈ।"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ਉਂਗਲ <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +602,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"ਚਿਹਰੇ ਦੀ ਪੁਸ਼ਟੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"ਤੁਸੀਂ ਚਿਹਰਾ ਅਣਲਾਕ ਸੈੱਟਅੱਪ ਨਹੀਂ ਕੀਤਾ ਹੈ।"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਚਿਹਰਾ ਅਣਲਾਕ ਦੀ ਸੁਵਿਧਾ ਨਹੀਂ ਹੈ।"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> <string name="face_name_template" msgid="3877037340223318119">"ਚਿਹਰਾ <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1328,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ਡੀਬੱਗਿੰਗ ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ਡੀਬੱਗਿੰਗ ਅਯੋਗ ਬਣਾਉਣ ਲਈ ਚੁਣੋ।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ ਨੂੰ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ ਨੂੰ ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ ਨੂੰ ਬੰਦ ਕਰਨ ਲਈ ਚੁਣੋ।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ਟੈਸਟ ਹਾਰਨੈੱਸ ਮੋਡ ਚਾਲੂ ਹੈ"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ਟੈਸਟ ਹਾਰਨੈੱਸ ਮੋਡ ਬੰਦ ਕਰਨ ਲਈ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਕਰੋ।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ਸੀਰੀਅਲ ਕੰਸੋਲ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string> @@ -1621,8 +1634,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> ਤੋਂ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਸ਼ੁਰੂ ਕੀਤੀ ਗਈ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਲਈ ਭਵਿੱਖੀ R ਬਿਲਡ ਵਿੱਚ \'ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ \'ਤੇ ਇਜਾਜ਼ਤ\' ਵਿਸ਼ੇਸ਼ਤਾ ਨਹੀਂ ਹੋਵੇਗੀ। ਕਿਰਪਾ ਕਰਕੇ go/r-bg-fgs-restriction ਦੇਖੋ ਅਤੇ ਬੱਗ ਰਿਪੋਰਟ ਫ਼ਾਈਲ ਕਰੋ।"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"ਕੀ ਵੌਲਿਊਮ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੇ ਪੱਧਰ ਤੋਂ ਵਧਾਉਣੀ ਹੈ?\n\nਲੰਮੇ ਸਮੇਂ ਤੱਕ ਉੱਚ ਵੌਲਿਊਮ ਤੇ ਸੁਣਨ ਨਾਲ ਤੁਹਾਡੀ ਸੁਣਨ ਸ਼ਕਤੀ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚ ਸਕਦਾ ਹੈ।"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਵਰਤਣਾ ਹੈ?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ਸ਼ਾਰਟਕੱਟਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ਰੱਦ ਕਰੋ"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ਸ਼ਾਰਟਕੱਟ ਬੰਦ ਕਰੋ"</string> @@ -1845,6 +1857,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"ਗੈਰ-ਸ਼੍ਰੇਣੀਕਿਰਤ"</string> <string name="importance_from_user" msgid="2782756722448800447">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string> <string name="importance_from_person" msgid="4235804979664465383">"ਇਹ ਸ਼ਾਮਲ ਲੋਕਾਂ ਦੇ ਕਾਰਨ ਮਹੱਤਵਪੂਰਨ ਹੈ।"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ (ਇਸ ਖਾਤੇ ਨਾਲ ਇੱਕ ਵਰਤੋਂਕਾਰ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ?"</string> <string name="language_selection_title" msgid="52674936078683285">"ਇੱਕ ਭਾਸ਼ਾ ਸ਼ਾਮਲ ਕਰੋ"</string> @@ -2018,20 +2032,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ਨਿੱਜੀ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ਕੰਮ"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਨਾਲ ਸਾਂਝਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ਨਿੱਜੀ ਐਪਾਂ ਨਾਲ ਸਾਂਝਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨਿੱਜੀ ਅਤੇ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਵਿਚਕਾਰ ਸਾਂਝਾਕਰਨ ਨੂੰ ਬਲਾਕ ਕੀਤਾ ਹੈ"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਚਾਲੂ ਕਰੋ"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਅਤੇ ਸੰਪਰਕਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ਕੋਈ ਐਪ ਉਪਲਬਧ ਨਹੀਂ"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ਅਸੀਂ ਕੋਈ ਐਪ ਨਹੀਂ ਲੱਭ ਸਕੇ"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ਟੈਲੀਫ਼ੋਨੀ ਕਾਲਾਂ ਵਿੱਚ ਰਿਕਾਰਡ ਕਰੋ ਜਾਂ ਆਡੀਓ ਚਲਾਓ"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"ਇਹ ਇਸ ਐਪ ਨੂੰ, ਪੂਰਵ-ਨਿਰਧਾਰਤ ਡਾਇਲਰ ਐਪਲੀਕੇਸ਼ਨ ਵਜੋਂ ਜਿੰਮੇ ਲਾਏ ਜਾਣ \'ਤੇ, ਟੈਲੀਫ਼ੋਨੀ ਕਾਲਾਂ ਵਿੱਚ ਰਿਕਾਰਡ ਕਰਨ ਜਾਂ ਆਡੀਓ ਚਲਾਉਣ ਦਿੰਦਾ ਹੈ।"</string> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 50e6974bb4e0..c4246fad9a3e 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Twoja organizacja zarządza tym urządzeniem i może monitorować ruch w sieci. Kliknij, by dowiedzieć się więcej."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Ustawienia lokalizacji zmienione przez administratora"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Kliknij, aby zobaczyć ustawienia lokalizacji."</string> + <string name="country_detector" msgid="7023275114706088854">"Wykrywanie kraju"</string> + <string name="location_service" msgid="2439187616018455546">"Usługa lokalizacyjna"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Usługa powiadomień czujnika"</string> + <string name="twilight_service" msgid="8964898045693187224">"Usługa Zmierzch"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Nie można użyć aplikacji administratora. Dane z urządzenia zostaną wykasowane.\n\nJeśli masz pytania, skontaktuj się z administratorem organizacji."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Drukowanie wyłączone przez: <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -251,6 +255,10 @@ <item quantity="other">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_1">%d</xliff:g> sekundy.</item> <item quantity="one">Zrzut ekranu do raportu o błędzie zostanie zrobiony za <xliff:g id="NUMBER_0">%d</xliff:g> sekundę.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tryb cichy"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Dźwięk jest wyłączony"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Dźwięk jest włączony"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Spróbuj ponownie."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nie zarejestrowano odcisków palców."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Czujnik jest tymczasowo wyłączony."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nie można zweryfikować twarzy. Spróbuj ponownie."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Rozpoznawanie twarzy nie jest skonfigurowane."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"To urządzenie nie obsługuje rozpoznawania twarzy."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Czujnik jest tymczasowo wyłączony."</string> <string name="face_name_template" msgid="3877037340223318119">"Twarz <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Podłączono moduł debugowania USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Kliknij, by wyłączyć debugowanie USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Wybierz, aby wyłączyć debugowanie USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Podłączono debugowanie bezprzewodowe"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Kliknij, by wyłączyć debugowanie bezprzewodowe"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Wybierz, by wyłączyć debugowanie bezprzewodowe."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Tryb jarzma testowego został włączony"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Przywróć ustawienia fabryczne, by wyłączyć tryb jarzma testowego."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Konsola szeregowa włączona"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Uruchomiona w tle usługa działająca w pierwszym planie z pakietu <xliff:g id="PACKAGENAME">%1$s</xliff:g> nie będzie miała uprawnień obowiązujących podczas używania w przyszłych kompilacjach R. Zapoznaj się z ograniczeniem go/r-bg-fgs-restriction i zgłoś błąd."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu do ułatwień dostępu?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Gdy skrót jest włączony, jednoczesne naciskanie przez trzy sekundy obu przycisków głośności uruchamia funkcję ułatwień dostępu."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edytuj skróty"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anuluj"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Wyłącz skrót"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Bez kategorii"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ustawiłeś ważność tych powiadomień."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g> (użytkownik dla tego konta już istnieje)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Dodaj język"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobiste"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Do pracy"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nie można udostępnić aplikacji do pracy"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nie można udostępnić aplikacji osobistej"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Administrator IT zablokował udostępnianie między aplikacjami osobistymi i aplikacjami do pracy"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Włącz aplikacje do pracy"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Włącz aplikacje do pracy, aby uzyskać dostęp do kontaktów i aplikacji do pracy"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Brak dostępnych aplikacji"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nie znaleźliśmy żadnych aplikacji"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Włącz profil do pracy"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Nagrywanie lub odtwarzanie dźwięku podczas połączeń telefonicznych"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Zezwala na odtwarzanie dźwięku podczas rozmów telefonicznych przez aplikację przypisaną jako domyślnie wybierającą numery."</string> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 5677ab2be353..dfb5beff86b5 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Sua organização gerencia este dispositivo e pode monitorar o tráfego de rede. Toque para ver detalhes."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Configurações de localização modificadas pelo administrador"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Toque para ver as configurações de localização."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector de país"</string> + <string name="location_service" msgid="2439187616018455546">"Serviço de localização"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Serviço de notificações do sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="one">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> <item quantity="other">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Som DESATIVADO"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O som está ATIVADO"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível verificar o rosto. Tente novamente."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"O desbloqueio facial não foi configurado."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -914,7 +920,7 @@ <string name="js_dialog_before_unload_title" msgid="7012587995876771246">"Confirmar navegação"</string> <string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"Sair desta página"</string> <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"Permanecer nesta página"</string> - <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nTem certeza que quer sair desta página?"</string> + <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nVocê quer mesmo sair desta página?"</string> <string name="save_password_label" msgid="9161712335355510035">"Confirmar"</string> <string name="double_tap_toast" msgid="7065519579174882778">"Dica: toque duas vezes para aumentar e diminuir o zoom."</string> <string name="autofill_this_form" msgid="3187132440451621492">"Preench. aut."</string> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração sem fio conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração sem fio"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecione para desativar a depuração sem fio."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo Arcabouço de testes ativado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Console serial ativado"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano por <xliff:g id="PACKAGENAME">%1$s</xliff:g> não receberá uma permissão durante o uso em futuras versões R. Consulte go/r-bg-fgs-restriction e crie um relatório de bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sem classificação"</string> <string name="importance_from_user" msgid="2782756722448800447">"Você definiu a importância dessas notificações."</string> <string name="importance_from_person" msgid="4235804979664465383">"Isso é importante por causa das pessoas envolvidas."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Não é possível compartilhar com apps de trabalho"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Não é possível compartilhar com apps pessoais"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Seu administrador de TI bloqueou o compartilhamento entre apps pessoais e de trabalho"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ativar apps de trabalho"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ative os apps de trabalho para acessar apps e contatos profissionais"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nenhum app disponível"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Não foi possível encontrar nenhum app"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ativar perfil de trabalho"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou tocar áudio em chamadas telefônicas"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permitir que esse app grave ou toque áudio em chamadas telefônicas quando for usado como aplicativo discador padrão."</string> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 4bdb07f75c23..00c56dd8be21 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"A sua entidade gere este dispositivo e pode monitorizar o tráfego de rede. Toque para obter mais detalhes."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Definições de localização alteradas pelo administrador"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Toque para ver as definições de localização."</string> + <string name="country_detector" msgid="7023275114706088854">"Detetor de país"</string> + <string name="location_service" msgid="2439187616018455546">"Serviço de localização"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Serviço de notificações do sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a aplicação de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> <item quantity="one">A tirar uma captura de ecrã do relatório de erro dentro de <xliff:g id="NUMBER_0">%d</xliff:g> segundo…</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Som desativado"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O som está ativado"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registada."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporariamente desativado."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível validar o rosto. Tente novamente."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Não configurou o Desbloqueio Através do Rosto."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Desbloqueio Através do Rosto não suportado neste dispositivo."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporariamente desativado."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB ligada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração por USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração sem fios ligada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração sem fios."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecione para desativar a depuração sem fios."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo de estrutura de teste ativado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Efetue uma reposição de dados de fábrica para desativar o Modo de estrutura de teste."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Consola de série ativada"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano de <xliff:g id="PACKAGENAME">%1$s</xliff:g> não terá a autorização durante a utilização em compilações R futuras. Aceda a go/r-bg-fgs-restriction e envie um relatório de erros."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir com um volume elevado durante longos períodos poderá ser prejudicial para a sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Pretende utilizar o atalho de acessibilidade?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sem categoria"</string> <string name="importance_from_user" msgid="2782756722448800447">"Definiu a importância destas notificações."</string> <string name="importance_from_person" msgid="4235804979664465383">"É importante devido às pessoas envolvidas."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Não é possível partilhar com apps de trabalho."</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Não é possível partilhar com apps pessoais."</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"O seu administrador de TI bloqueou a partilha entre as apps de trabalho e pessoais."</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ative as apps de trabalho."</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ative as apps de trabalho para aceder às apps de trabalho e aos contactos."</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nenhuma app disponível."</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Não foi possível encontrar quaisquer apps."</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ativar perfil de trabalho"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou reproduzir áudio em chamadas telefónicas"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite que esta app, quando atribuída como uma aplicação de telefone predefinida, grave ou reproduza áudio em chamadas telefónicas."</string> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 5677ab2be353..dfb5beff86b5 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Sua organização gerencia este dispositivo e pode monitorar o tráfego de rede. Toque para ver detalhes."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Configurações de localização modificadas pelo administrador"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Toque para ver as configurações de localização."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector de país"</string> + <string name="location_service" msgid="2439187616018455546">"Serviço de localização"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Serviço de notificações do sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Serviço de crepúsculo"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="one">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> <item quantity="other">Capturas de tela para o relatório de bug serão feitas em <xliff:g id="NUMBER_1">%d</xliff:g> segundos.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Som DESATIVADO"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O som está ATIVADO"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tente novamente."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível verificar o rosto. Tente novamente."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"O desbloqueio facial não foi configurado."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string> <string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -914,7 +920,7 @@ <string name="js_dialog_before_unload_title" msgid="7012587995876771246">"Confirmar navegação"</string> <string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"Sair desta página"</string> <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"Permanecer nesta página"</string> - <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nTem certeza que quer sair desta página?"</string> + <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nVocê quer mesmo sair desta página?"</string> <string name="save_password_label" msgid="9161712335355510035">"Confirmar"</string> <string name="double_tap_toast" msgid="7065519579174882778">"Dica: toque duas vezes para aumentar e diminuir o zoom."</string> <string name="autofill_this_form" msgid="3187132440451621492">"Preench. aut."</string> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração sem fio conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração sem fio"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecione para desativar a depuração sem fio."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo Arcabouço de testes ativado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Console serial ativado"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano por <xliff:g id="PACKAGENAME">%1$s</xliff:g> não receberá uma permissão durante o uso em futuras versões R. Consulte go/r-bg-fgs-restriction e crie um relatório de bug."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editar atalhos"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Cancelar"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Desativar atalho"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Sem classificação"</string> <string name="importance_from_user" msgid="2782756722448800447">"Você definiu a importância dessas notificações."</string> <string name="importance_from_person" msgid="4235804979664465383">"Isso é importante por causa das pessoas envolvidas."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Não é possível compartilhar com apps de trabalho"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Não é possível compartilhar com apps pessoais"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Seu administrador de TI bloqueou o compartilhamento entre apps pessoais e de trabalho"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ativar apps de trabalho"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ative os apps de trabalho para acessar apps e contatos profissionais"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nenhum app disponível"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Não foi possível encontrar nenhum app"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ativar perfil de trabalho"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Gravar ou tocar áudio em chamadas telefônicas"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permitir que esse app grave ou toque áudio em chamadas telefônicas quando for usado como aplicativo discador padrão."</string> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 99cdc0bd4b02..e4eaf803c5ab 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -195,6 +195,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizația dvs. gestionează acest dispozitiv și poate monitoriza traficul în rețea. Atingeți pentru mai multe detalii."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Setările privind locația au fost modificate de administrator"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Atingeți pentru a vedea setările privind locația."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector de țară"</string> + <string name="location_service" msgid="2439187616018455546">"Servicii de localizare"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Serviciu pentru notificări de la senzori"</string> + <string name="twilight_service" msgid="8964898045693187224">"Serviciul Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi utilizată. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -248,6 +252,10 @@ <item quantity="other">Peste <xliff:g id="NUMBER_1">%d</xliff:g> de secunde se va realiza o captură de ecran pentru raportul de eroare.</item> <item quantity="one">Peste <xliff:g id="NUMBER_0">%d</xliff:g> secundă se va realiza o captură de ecran pentru raportul de eroare.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mod Silențios"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sunetul este DEZACTIVAT"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sunetul este ACTIVAT"</string> @@ -549,8 +557,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Încercați din nou."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nu au fost înregistrate amprente."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzorul este dezactivat temporar."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +601,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nu se poate confirma fața. Încercați din nou."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nu ați configurat deblocarea facială."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Deblocarea facială nu este acceptată pe dispozitiv."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzorul este dezactivat temporar."</string> <string name="face_name_template" msgid="3877037340223318119">"Chip <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1338,6 +1344,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Remedierea erorilor prin USB este conectată"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Atingeți pentru a dezactiva remedierea erorilor prin USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selectați pentru a dezactiva remedierea erorilor prin USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Remedierea erorilor prin wireless este activă"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Atingeți pentru a dezactiva remedierea erorilor prin wireless"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selectați pentru a dezactiva remedierea erorilor prin wireless."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modul Set de testare este activat"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Reveniți la setările din fabrică pentru a dezactiva modul Set de testare."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Consola din serie este activată"</string> @@ -1643,8 +1652,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Serviciul în prim-plan inițializat în fundal din <xliff:g id="PACKAGENAME">%1$s</xliff:g> nu va avea permisiunea în timpul utilizării în versiunile R viitoare. Consultați go/r-bg-fgs-restriction și trimiteți un raport de eroare."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utilizați comanda rapidă pentru accesibilitate?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Atunci când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de trei secunde, veți lansa o funcție de accesibilitate."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editați comenzile rapide"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anulați"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Dezactivați comanda rapidă"</string> @@ -1877,6 +1885,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Neclasificate"</string> <string name="importance_from_user" msgid="2782756722448800447">"Dvs. setați importanța acestor notificări."</string> <string name="importance_from_person" msgid="4235804979664465383">"Notificarea este importantă având în vedere persoanele implicate."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>? (există deja un utilizator cu acest cont)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Adăugați o limbă"</string> @@ -2052,20 +2062,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Serviciu"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nu se poate trimite către aplicații pentru lucru"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nu se poate trimite către aplicații personale"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Administratorul IT a blocat trimiterea între aplicațiile personale și pentru lucru"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Activați aplicațiile pentru lucru"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Activați aplicațiile pentru lucru ca să le accesați pe acestea și persoanele de contact"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nicio aplicație disponibilă"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nu s-a găsit nicio aplicație"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Comutați la profilul de lucru"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Înregistrează sau redă conținut audio în apelurile telefonice"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Permite acestei aplicații, atunci când este setată ca aplicație telefon prestabilită, să înregistreze sau să redea conținut audio în apelurile telefonice."</string> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 244d0e680d18..7cd16332740d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша организация управляет этим устройством и может отслеживать сетевой трафик. Подробнее…"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Настройки геолокации изменены администратором"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Нажмите, чтобы открыть настройки геолокации."</string> + <string name="country_detector" msgid="7023275114706088854">"Определение страны"</string> + <string name="location_service" msgid="2439187616018455546">"Геолокация"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Сервис для обработки уведомлений от датчиков"</string> + <string name="twilight_service" msgid="8964898045693187224">"Сервис для определения наступления сумерек"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Невозможно использовать приложение для администрирования. С устройства будут удалены все данные.\n\nЕсли у вас возникли вопросы, обратитесь к администратору."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Функция печати отключена приложением \"<xliff:g id="OWNER_APP">%s</xliff:g>\""</string> @@ -251,6 +255,10 @@ <item quantity="many">Скриншот будет сделан через <xliff:g id="NUMBER_1">%d</xliff:g> секунд</item> <item quantity="other">Скриншот будет сделан через <xliff:g id="NUMBER_1">%d</xliff:g> секунды</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Режим без звука"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Выключить"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Включить"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Повторите попытку."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Нет отсканированных отпечатков пальцев"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сканер отпечатков пальцев временно отключен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Отпечаток <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Не удалось распознать лицо. Повторите попытку."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Вы не настроили фейсконтроль."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Это устройство не поддерживает функцию \"Фейсконтроль\"."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик временно отключен."</string> <string name="face_name_template" msgid="3877037340223318119">"Лицо <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -758,7 +764,7 @@ <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string> <string name="eventTypeCustom" msgid="3257367158986466481">"Особый"</string> <string name="eventTypeBirthday" msgid="7770026752793912283">"День рождения"</string> - <string name="eventTypeAnniversary" msgid="4684702412407916888">"Юбилей"</string> + <string name="eventTypeAnniversary" msgid="4684702412407916888">"Годовщина"</string> <string name="eventTypeOther" msgid="530671238533887997">"Другой"</string> <string name="emailTypeCustom" msgid="1809435350482181786">"Новый тип"</string> <string name="emailTypeHome" msgid="1597116303154775999">"Личный"</string> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Отладка по USB разрешена"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Нажмите, чтобы отключить отладку по USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Нажмите, чтобы отключить отладку по USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Отладка по Wi-Fi активна"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Нажмите, чтобы отключить отладку по Wi-Fi."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Нажмите, чтобы отключить отладку по Wi-Fi."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Тестовый режим включен"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Чтобы отключить тестовый режим, сбросьте настройки до заводских."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Консоль последовательного порта включена"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Службы из пакета <xliff:g id="PACKAGENAME">%1$s</xliff:g>, переведенные из фонового режима в активный, не будут получать разрешение while-in-use в будущих сборках на языке R. Перейдите на страницу go/r-bg-fgs-restriction и отправьте отчет об ошибке."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Установить громкость выше рекомендуемого уровня?\n\nВоздействие громкого звука в течение долгого времени может привести к повреждению слуха."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Использовать быстрое включение?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте обе кнопки регулировки громкости в течение трех секунд."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Изменить быстрые клавиши"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Отмена"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Деактивировать быстрое включение"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Без категории"</string> <string name="importance_from_user" msgid="2782756722448800447">"Вы определяете важность этих уведомлений."</string> <string name="importance_from_person" msgid="4235804979664465383">"Важное (люди)"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g> (пользователь с этим аккаунтом уже существует)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Добавьте язык"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Личный"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Рабочий"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Нельзя обмениваться данными с рабочими приложениями"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Нельзя обмениваться данными с личными приложениями"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Обмен данными между личными и рабочими приложениями заблокирован системным администратором."</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Включите рабочие приложения"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Включите рабочие приложения, чтобы получить доступ к ним и контактам."</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Нет доступных приложений"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Приложения не найдены."</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Включить рабочий профиль"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Запись и воспроизведение телефонных разговоров"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Если это приложение используется для звонков по умолчанию, оно сможет записывать и воспроизводить телефонные разговоры."</string> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 6583f942fd4b..37db789d1c32 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"ඔබගේ ආයතනය මෙම උපාංගය කළමනාකරණය කරන අතර එය ජාල තදබදය නිරීක්ෂණය කළ හැක. විස්තර සඳහා තට්ටු කරන්න."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"ස්ථාන සැකසීම් ඔබේ පරිපාලක විසින් වෙනස් කරන ලදී"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"ඔබේ ස්ථාන සැකසීම් බැලීමට තට්ටු කරන්න."</string> + <string name="country_detector" msgid="7023275114706088854">"රටවල් අනාවරකය"</string> + <string name="location_service" msgid="2439187616018455546">"ස්ථාන සේවාව"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"සංවේදක දැනුම් දීමේ සේවාව"</string> + <string name="twilight_service" msgid="8964898045693187224">"ඇඳිරි සේවාව"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string> <string name="factory_reset_message" msgid="2657049595153992213">"පරිපාලක යෙදුම භාවිතා කළ නොහැකිය. ඔබේ උපාංගය දැන් මකා දමනු ඇත.\n\nඔබට ප්රශ්න තිබේ නම්, ඔබේ සංවිධානයේ පරිපාලකට අමතන්න."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> විසින් මුද්රණය කිරීම අබල කර ඇත."</string> @@ -245,6 +249,10 @@ <item quantity="one">තත්පර <xliff:g id="NUMBER_1">%d</xliff:g>කින් දෝෂ වාර්තාව සඳහා තිර රුවක් ලබා ගනිමින්</item> <item quantity="other">තත්පර <xliff:g id="NUMBER_1">%d</xliff:g>කින් දෝෂ වාර්තාව සඳහා තිර රුවක් ලබා ගනිමින්</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"නිහඬ ආකාරය"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ශබ්දය අක්රියයි"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"හඬ ක්රියාත්මකයි"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"නැවත උත්සාහ කරන්න."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ඇඟිලි සලකුණු ඇතුළත් කර නොමැත."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"ඇඟිලි <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"මුහුණ සත්යාපන කළ නොහැක. නැවත උත්සාහ කරන්න."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"ඔබ මුහුණු අඟුලු ඇරීම සකසා නැත"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"මෙම උපාංගයෙහි මුහුණු අඟුලු ඇරීමට සහය නොදැක්වේ"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string> <string name="face_name_template" msgid="3877037340223318119">"මුහුණු <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1320,6 +1326,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB නිදොස්කරණය සම්බන්ධිතයි"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB නිදොස් කිරීම ක්රියාවිරහිත කිරීමට තට්ටු කරන්න"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB නිදොස්කරණය අබල කිරීමට තෝරන්න."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"නොරැහැන් නිදොස්කරණය සම්බන්ධ විය"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"නොරැහැන් නිදොස්කරණය ක්රියාවිරහිත කිරීමට තට්ටු කරන්න"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"නොරැහැන් නිදොස්කරණය අබල කිරීමට තෝරන්න."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"පුරක පරීක්ෂා ප්රකාරය සබලයි"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"පුරක පරීක්ෂා ප්රකාරය අබල කිරීමට කර්මාන්තශාලා යළි සැකසීමක් ඉටු කරන්න."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"අනුක්රමික කොන්සෝලය සබලයි"</string> @@ -1623,8 +1632,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> වෙතින් පසුබිම ආරම්භ කරන ලද පෙරබිම් සේවාව අනාගත R තැනුම්වලදී භාවිතයේ අවසරය නැත. කරුණාකර go/r-bg-fgs-අවහිරතාව බලා දෝෂ වාර්තාවක් ගොනු කරන්න."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"නිර්දේශිතයි මට්ටමට වඩා ශබ්දය වැඩිද?\n\nදිගු කාලයක් සඳහා ඉහළ ශබ්දයක් ඇසීමෙන් ඇතැම් විට ඔබගේ ඇසීමට හානි විය හැක."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ප්රවේශ්යතා කෙටිමඟ භාවිතා කරන්නද?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"කෙටිමග ක්රියාත්මක විට, හඬ පරිමා බොත්තම් දෙකම තත්පර 3ක් තිස්සේ එබීමෙන් ප්රවේශ්යතා විශේෂාංගය ආරම්භ වනු ඇත."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"කෙටිමං සංස්කරණ කරන්න"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"අවලංගු කරන්න"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"කෙටිමඟ ක්රියාවිරහිත කරන්න"</string> @@ -1847,6 +1855,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"වර්ගීකරණය නොකළ"</string> <string name="importance_from_user" msgid="2782756722448800447">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string> <string name="importance_from_person" msgid="4235804979664465383">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද (මෙම ගිණුම සහිත පරිශීලකයෙකු දැනටමත් සිටී) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද ?"</string> <string name="language_selection_title" msgid="52674936078683285">"භාෂාවක් එක් කරන්න"</string> @@ -2020,20 +2030,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"පුද්ගලික"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"කාර්යාල"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"කාර්යාල යෙදුම් සමග බෙදා ගැනීමට නොහැකිය"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"පෞද්ගලික යෙදුම් සමග බෙදා ගැනීමට නොහැකිය"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ඔබේ IT පරිපාලක පෞද්ගලික සහ කාර්යාල යෙදුම් අතර බෙදා ගැනීම අවහිර කළා"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"කාර්යාල යෙදුම් ක්රියාත්මක කරන්න"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"කාර්යාල යෙදුම් & සම්බන්ධතා වෙත ප්රවේශ වීමට කාර්යාල යෙදුම් ක්රියාත්මක කරන්න"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ලබා ගත හැකි යෙදුම් නැත"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"අපට කිසිදු යෙදුමක් සොයා ගැනීමට නොහැකි විය"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"කාර්යාලයට මාරු කරන්න"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ටෙලිෆොනි ඇමතුම්වලින් ඕඩියෝ පටිගත කරන්න නැතහොත් වාදනය කරන්න"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"පෙරනිමි ඩයලන යෙදුමක් ලෙස පැවරූ විට, මෙම යෙදුමට ටෙලිෆොනි ඇමතුම්වලින් ඕඩියෝ පටිගත කිරීමට හෝ වාදනය කිරීමට ඉඩ දෙයි."</string> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index d8006e7f8d12..3be2f09bb621 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizácia spravuje toto zariadenie a môže sledovať sieťovú premávku. Klepnutím zobrazíte podrobnosti."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Nastavenia polohy zmenil váš správca"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Klepnutím zobrazíte nastavenia polohy."</string> + <string name="country_detector" msgid="7023275114706088854">"Detektor krajiny"</string> + <string name="location_service" msgid="2439187616018455546">"Služba určovania polohy"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Služba upozornení senzora"</string> + <string name="twilight_service" msgid="8964898045693187224">"Služba stmievania"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -251,6 +255,10 @@ <item quantity="other">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_1">%d</xliff:g> sekúnd.</item> <item quantity="one">Snímka obrazovky pre hlásenie chyby sa vytvorí o <xliff:g id="NUMBER_0">%d</xliff:g> sekundu.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tichý režim"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvuk je VYPNUTÝ."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvuk je zapnutý"</string> @@ -437,7 +445,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"Táto oprávnená alebo systémová aplikácia môže kedykoľvek fotiť a nahrávať videá fotoaparátom systému. Aplikácia musí mať tiež povolenie android.permission.CAMERA."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"ovládať vibrovanie"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Umožňuje aplikácii ovládať vibrácie."</string> - <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Povoľuje aplikácii získať prístup k stavu vibrácií."</string> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Povoľuje aplikácii prístup k stavu vibrátora."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"priamo volať na telefónne čísla"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na tiesňovú linku."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"prístup k službe volania IMS"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Skúste to znova"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neregistrovali ste žiadne odtlačky prstov."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasne vypnutý."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nedá sa overiť tvár. Skúste to znova."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nenastavili ste odomknutie tvárou."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Toto zariadenie nepodporuje odomknutie tvárou."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasne vypnutý."</string> <string name="face_name_template" msgid="3877037340223318119">"Tvár <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Ladenie cez USB pripojené"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Klepnutím vypnite ladenie cez USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Vyberte, ak chcete zakázať ladenie cez USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Bezdrôtové ladenie je pripojené"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Klepnutím vypnete bezdrôtové ladenie"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Výberom zakážete bezdrôtové ladenie."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Režim správcu testov je aktivovaný"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Ak chcete zakázať režim správcu testov, obnovte výrobné nastavenia."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Sériová konzola je povolená"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Služba na popredí spustená na pozadí z balíka <xliff:g id="PACKAGENAME">%1$s</xliff:g> nebude mať v budúcich zostavách R povolenie Počas používania. Prejdite na go/r-bg-fgs-restriction a odošlite hlásenie chyby."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšiť hlasitosť nad odporúčanú úroveň?\n\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použiť skratku dostupnosti?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upraviť skratky"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Zrušiť"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vypnúť skratku"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Nekategorizované"</string> <string name="importance_from_user" msgid="2782756722448800447">"Nastavili ste dôležitosť týchto upozornení."</string> <string name="importance_from_person" msgid="4235804979664465383">"Táto správa je dôležitá vzhľadom na osoby, ktorých sa to týka."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g> (používateľ s týmto účtom už existuje)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Pridať jazyk"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobné"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Práca"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nedá sa zdieľa s pracovnými aplikáciami"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nedá sa zdieľať s osobnými aplikáciami"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Váš správca IT zablokoval zdieľanie medzi osobnými a pracovnými aplikáciami"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Zapnite pracovné aplikácie"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ak chcete získať prístup k pracovným aplikáciám a kontaktom, zapnite pracovné aplikácie"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"K dispozícii nie sú žiadne aplikácie"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Neboli nájdené žiadne aplikácie"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Zapnúť pracovný profil"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Nahrávanie alebo prehrávanie zvuku počas telefonických hovorov"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Povoľuje tejto aplikácii, keď je priradená ako predvolená aplikácia na vytáčanie, nahrávať alebo prehrávať zvuk počas telefonických hovorov."</string> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 93a1d34560a5..71786011f2ce 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja to napravo in lahko nadzira omrežni promet. Dotaknite se za podrobnosti."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Skrbnik je spremenil nastavitve lokacije"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Dotaknite se za ogled nastavitev lokacije."</string> + <string name="country_detector" msgid="7023275114706088854">"Zaznavalnik države"</string> + <string name="location_service" msgid="2439187616018455546">"Lokacijska storitev"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Storitev obvestil tipal"</string> + <string name="twilight_service" msgid="8964898045693187224">"Storitev Somrak"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -251,6 +255,10 @@ <item quantity="few">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item> <item quantity="other">Posnetek zaslona za poročilo o napakah bo narejen čez <xliff:g id="NUMBER_1">%d</xliff:g> s.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tihi način"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zvok je IZKLOPLJEN"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zvok je VKLOPLJEN"</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Poskusite znova."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni včlanjenih prstnih odtisov."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Obraza ni mogoče preveriti. Poskusite znova."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Odklepanja z obrazom niste nastavili."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ta naprava ne podpira odklepanja z obrazom."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Tipalo je začasno onemogočeno."</string> <string name="face_name_template" msgid="3877037340223318119">"Obraz <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Iskanje napak prek USB je povezano"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Dotaknite se, če želite izklop. odpravlj. napak prek USB-ja"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Izberite, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Povezava za brezžično odpravljanje napak je vzpostavljena"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Dotaknite se, če želite izklopiti brezžično odpravljanje napak."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Izberite, če želite onemogočiti brezžično odpravljanje napak."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Način preizkusnega ogrodja je omogočen"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Če želite onemogočiti način preizkusnega ogrodja, ponastavite napravo na tovarniške nastavitve."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serijska konzola je omogočena"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"V prihodnjih različicah R storitev v ospredju z zagonom iz ozadja iz paketa <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne bo imela dovoljenja med uporabo aplikacije. Oglejte si go/r-bg-fgs-restriction in pošljite poročilo o napakah."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ali želite povečati glasnost nad priporočeno raven?\n\nDolgotrajno poslušanje pri veliki glasnosti lahko poškoduje sluh."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite uporabljati bližnjico funkcij za ljudi s posebnimi potrebami?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi bližnjice"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Prekliči"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Izklopi bližnjico"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Nekategorizirano"</string> <string name="importance_from_user" msgid="2782756722448800447">"Vi določite raven pomembnosti teh obvestil."</string> <string name="importance_from_person" msgid="4235804979664465383">"Pomembno zaradi udeleženih ljudi."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g> (uporabnik s tem računom že obstaja)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Dodajanje jezika"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osebno"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Služba"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Deljenje z delovnimi aplikacijami ni mogoče"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Deljenje z osebnimi aplikacijami ni mogoče"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Skrbnik za IT je blokiral deljenje med osebnimi in delovnimi aplikacijami"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Vklopi delovne aplikacije"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Če želite dostopati do delovnih aplikacij in stikov, vklopite delovne aplikacije"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Na voljo ni nobena aplikacija"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Aplikacij ni bilo mogoče najti"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Vklopi delovni profil"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Snemanje ali predvajanje zvoka med telefonskimi klici"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tej aplikaciji dovoljuje snemanje ali predvajanje zvoka med telefonskimi klici, ko je nastavljena kot privzeta aplikacija za klicanje."</string> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index f708fe41e737..244852110835 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizata jote e menaxhon këtë pajisje dhe mund të monitorojë trafikun e rrjetit. Trokit për detaje."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Cilësimet e vendndodhjes u ndryshuan nga administratori yt"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Trokit për të parë cilësimet e tua të vendndodhjes."</string> + <string name="country_detector" msgid="7023275114706088854">"Zbuluesi i shtetit"</string> + <string name="location_service" msgid="2439187616018455546">"Vendndodhja e shërbimit"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Shërbimi i njoftimeve të sensorit"</string> + <string name="twilight_service" msgid="8964898045693187224">"Shërbimi i muzgut"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Aplikacioni i administratorit nuk mund të përdoret. Pajisja jote tani do të fshihet.\n\nNëse ke pyetje, kontakto me administratorin e organizatës."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Printimi është çaktivizuar nga <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Marrja e pamjes së ekranit për raportin e defektit në kod në <xliff:g id="NUMBER_1">%d</xliff:g> sekonda.</item> <item quantity="one">Marrja e pamjes së ekranit për raportin e defektit në kod në <xliff:g id="NUMBER_0">%d</xliff:g> sekondë.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modaliteti \"në heshtje\""</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Zëri është çaktivizuar"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Zëri është i aktivizuar"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Provo përsëri."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nuk ka asnjë gjurmë gishti të regjistruar."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensori është çaktivizuar përkohësisht."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Fytyra nuk mund të verifikohet. Provo përsëri."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nuk e ke konfiguruar shkyçjen me fytyrë."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Shkyçja me fytyrë nuk mbështetet në këtë pajisje"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensori është çaktivizuar përkohësisht."</string> <string name="face_name_template" msgid="3877037340223318119">"Fytyra <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1285,7 +1291,7 @@ <string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"Mos lejo asnjëherë"</string> <string name="sim_removed_title" msgid="5387212933992546283">"Karta SIM u hoq"</string> <string name="sim_removed_message" msgid="9051174064474904617">"Rrjeti celular nuk do të mundësohet derisa ta rinisësh pajisjen me një kartë të vlefshme SIM në të."</string> - <string name="sim_done_button" msgid="6464250841528410598">"U krye!"</string> + <string name="sim_done_button" msgid="6464250841528410598">"U krye"</string> <string name="sim_added_title" msgid="7930779986759414595">"Karta SIM u shtua"</string> <string name="sim_added_message" msgid="6602906609509958680">"Rinise pajisjen për të pasur qasje në rrjetin celular."</string> <string name="sim_restart_button" msgid="8481803851341190038">"Rifillo"</string> @@ -1298,7 +1304,7 @@ <string name="time_picker_dialog_title" msgid="9053376764985220821">"Cakto kohën"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Vendos datën"</string> <string name="date_time_set" msgid="4603445265164486816">"Cakto"</string> - <string name="date_time_done" msgid="8363155889402873463">"U krye!"</string> + <string name="date_time_done" msgid="8363155889402873463">"U krye"</string> <string name="perms_new_perm_prefix" msgid="6984556020395757087"><font size="12" fgcolor="#ff33b5e5">"E RE: "</font></string> <string name="perms_description_app" msgid="2747752389870161996">"Ofruar nga <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="no_permissions" msgid="5729199278862516390">"Nuk kërkohen leje"</string> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Korrigjuesi i USB-së është i lidhur"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Trokit për të çaktivizuar korrigjimin e USB-së"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Përzgjidhe për të çaktivizuar korrigjimin e gabimeve të USB-së"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Korrigjimi me lidhjen pa tel është lidhur"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Trokit për të çaktivizuar korrigjimin me lidhjen pa tel"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Zgjidhe për të çaktivizuar korrigjimin me lidhjen pa tel"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modaliteti i lidhjes së testimit është aktivizuar"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Kryej një rivendosje në cilësimet e fabrikës për të çaktivizuar \"Modalitetin e lidhjes së testimit\"."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Paneli komandues i serisë është aktivizuar"</string> @@ -1401,7 +1410,7 @@ <string name="ime_action_search" msgid="4501435960587287668">"Kërko"</string> <string name="ime_action_send" msgid="8456843745664334138">"Dërgo"</string> <string name="ime_action_next" msgid="4169702997635728543">"Përpara"</string> - <string name="ime_action_done" msgid="6299921014822891569">"U krye!"</string> + <string name="ime_action_done" msgid="6299921014822891569">"U krye"</string> <string name="ime_action_previous" msgid="6548799326860401611">"I mëparshëm"</string> <string name="ime_action_default" msgid="8265027027659800121">"Ekzekuto"</string> <string name="dial_number_using" msgid="6060769078933953531">"Telefono numrin\nduke përdorur <xliff:g id="NUMBER">%s</xliff:g>"</string> @@ -1448,7 +1457,7 @@ <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> nga gjithsej <xliff:g id="TOTAL">%d</xliff:g></item> <item quantity="one">1 përputhje</item> </plurals> - <string name="action_mode_done" msgid="2536182504764803222">"U krye!"</string> + <string name="action_mode_done" msgid="2536182504764803222">"U krye"</string> <string name="progress_erasing" msgid="6891435992721028004">"Po fshin hapësirën ruajtëse të brendshme…"</string> <string name="share" msgid="4157615043345227321">"Shpërndaj"</string> <string name="find" msgid="5015737188624767706">"Gjej"</string> @@ -1489,7 +1498,7 @@ <string name="keyboardview_keycode_alt" msgid="8997420058584292385">"Alt"</string> <string name="keyboardview_keycode_cancel" msgid="2134624484115716975">"Anulo"</string> <string name="keyboardview_keycode_delete" msgid="2661117313730098650">"Fshi"</string> - <string name="keyboardview_keycode_done" msgid="2524518019001653851">"U krye!"</string> + <string name="keyboardview_keycode_done" msgid="2524518019001653851">"U krye"</string> <string name="keyboardview_keycode_mode_change" msgid="2743735349997999020">"Ndryshim modaliteti"</string> <string name="keyboardview_keycode_shift" msgid="3026509237043975573">"Shift"</string> <string name="keyboardview_keycode_enter" msgid="168054869339091055">"Enter"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Shërbimi në plan të parë i nisur në sfond nga <xliff:g id="PACKAGENAME">%1$s</xliff:g> nuk do të ketë lejen e nevojshme gjatë përdorimit në ndërtimet e ardhshme R. Shiko go/r-bg-fgs-restriction dhe dërgo një raport të defekteve në kod."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Të ngrihet volumi mbi nivelin e rekomanduar?\n\nDëgjimi me volum të lartë për periudha të gjata mund të dëmtojë dëgjimin."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Të përdoret shkurtorja e qasshmërisë?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redakto shkurtoret"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Anulo"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Çaktivizo shkurtoren"</string> @@ -1747,7 +1755,7 @@ <string name="immersive_cling_title" msgid="2307034298721541791">"Po shikon ekranin e plotë"</string> <string name="immersive_cling_description" msgid="7092737175345204832">"Për të dalë, rrëshqit nga lart poshtë."</string> <string name="immersive_cling_positive" msgid="7047498036346489883">"E kuptova"</string> - <string name="done_label" msgid="7283767013231718521">"U krye!"</string> + <string name="done_label" msgid="7283767013231718521">"U krye"</string> <string name="hour_picker_description" msgid="5153757582093524635">"Rrëshqitësi rrethor i orëve"</string> <string name="minute_picker_description" msgid="9029797023621927294">"Rrëshqitësi rrethor i minutave"</string> <string name="select_hours" msgid="5982889657313147347">"Përzgjidh orët"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"E pakategorizuara"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ke caktuar rëndësinë e këtyre njoftimeve."</string> <string name="importance_from_person" msgid="4235804979664465383">"Është i rëndësishëm për shkak të personave të përfshirë."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> (një përdorues me këtë llogari ekziston tashmë) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Shto një gjuhë"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Puna"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Nuk mund të ndash me aplikacionet e punës"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Nuk mund të ndash me aplikacionet personale"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Administratori yt i teknologjisë së informacionit ka bllokuar ndarjen mes aplikacioneve personale dhe atyre të punës"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktivizo aplikacionet e punës"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktivizo aplikacionet e punës për të pasur qasje tek aplikacionet dhe kontaktet e punës"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Nuk ofrohet asnjë aplikacion"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Nuk mund të gjenim asnjë aplikacion"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Kalo në profilin e punës"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Të regjistrojë ose luajë audio në telefonata"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Lejon këtë aplikacion, kur caktohet si aplikacioni i parazgjedhur i formuesit të numrave, të regjistrojë ose luajë audio në telefonata."</string> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 51e26749935a..3edfdb1c01a7 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -195,6 +195,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Организација управља овим уређајем и може да надгледа мрежни саобраћај. Додирните за детаље."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Администратор је променио подешавања локације"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Додирните да бисте видели подешавања локације."</string> + <string name="country_detector" msgid="7023275114706088854">"Детектор земље"</string> + <string name="location_service" msgid="2439187616018455546">"Услуга локације"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Услуга обавештења сензора"</string> + <string name="twilight_service" msgid="8964898045693187224">"Услуга Сумрак"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, контактирајте администратора организације."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -248,6 +252,10 @@ <item quantity="few">Направићемо снимак екрана ради извештаја о грешци за <xliff:g id="NUMBER_1">%d</xliff:g> секунде.</item> <item quantity="other">Направићемо снимак екрана ради извештаја о грешци за <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Нечујни режим"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Звук је ИСКЉУЧЕН"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Звук је УКЉУЧЕН"</string> @@ -549,8 +557,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Пробајте поново."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Није регистрован ниједан отисак прста."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензор је привремено онемогућен."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -594,8 +601,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Провера лица није успела. Пробајте поново."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Нисте подесили откључавање лицем"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Откључавање лицем није подржано на овом уређају"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Сензор је привремено онемогућен."</string> <string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1338,6 +1344,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Отклањање грешака са USB-а је омогућено"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Додирните да бисте искључили отклањање грешака са USB-а"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Изаберите да бисте онемогућили отклањања грешака са USB-а."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Бежично отклањање грешака је повезано"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Додирните да бисте искључили бежично отклањање грешака"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Изаберите да бисте онемогућили бежично отклањање грешака."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Омогућен је режим пробног коришћења"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Обавите ресетовање на фабричка подешавања да бисте онемогућили режим пробног коришћења."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Серијска конзола је омогућена"</string> @@ -1643,8 +1652,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Услуга у првом плану са <xliff:g id="PACKAGENAME">%1$s</xliff:g> која је покренута у позадини неће имати дозволу током коришћења у будућим R верзијама. Посетите go/r-bg-fgs-restriction и пошаљите извештај о грешци."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Желите ли да користите пречицу за приступачност?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Измените пречице"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Откажи"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Искључи пречицу"</string> @@ -1877,6 +1885,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Некатегоризовано"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ви подешавате важност ових обавештења."</string> <string name="importance_from_person" msgid="4235804979664465383">"Ово је важно због људи који учествују."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g> (корисник са тим налогом већ постоји)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Додајте језик"</string> @@ -2052,20 +2062,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Пословни"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Не можете да делите садржај са апликацијама за посао"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Не можете да делите садржај са личним апликацијама"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ИТ администратор је блокирао дељење између личних апликација и апликација за посао"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Укључите апликације за посао"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Укључите апликације за посао да бисте приступили апликацијама и контактима за посао"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Нема доступних апликација"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Нисмо пронашли ниједну апликацију"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Укључи профил за Work"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Снимање или пуштање звука у телефонским позивима"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Омогућава овој апликацији, када је додељена као подразумевана апликација за позивање, да снима или пушта звук у телефонским позивима."</string> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 88b62f439ba2..73e7efc4ab8d 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Organisationen hanterar den här enheten och kan övervaka nätverkstrafiken. Tryck om du vill veta mer."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Platsinställningarna har ändrats av administratören"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Tryck för att se dina platsinställningar."</string> + <string name="country_detector" msgid="7023275114706088854">"Country Detector"</string> + <string name="location_service" msgid="2439187616018455546">"Location Service"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensor Notification Service"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Det går inte att använda administratörsappen. Enheten rensas.\n\nKontakta organisationens administratör om du har några frågor."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Utskrift har inaktiverats av <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Tar en skärmdump till felrapporten om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder.</item> <item quantity="one">Tar en skärmdump till felrapporten om <xliff:g id="NUMBER_0">%d</xliff:g> sekund.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Tyst läge"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ljudet är AV"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ljudet är PÅ"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Försök igen."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Inga fingeravtryck har registrerats."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Det gick inte att verifiera ansiktet. Försök igen."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Du har inte konfigurerat ansiktslås."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås stöds inte på den här enheten."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensorn har tillfälligt inaktiverats."</string> <string name="face_name_template" msgid="3877037340223318119">"Ansikte <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-felsökning ansluten"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Tryck för att inaktivera USB-felsökning"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Välj för att inaktivera USB-felsökning."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Trådlös felsökning ansluten"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tryck för att inaktivera trådlös felsökning"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Välj för att inaktivera trådlös felsökning."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Läget för testverktyg har aktiverats"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Inaktivera testverktygsläget genom att göra en återställning till standardinställningarna."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Seriekonsolen är aktiverad"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Förgrundstjänsten från <xliff:g id="PACKAGENAME">%1$s</xliff:g> som startades i bakgrunden får inte behörighet som gäller vid användning i framtida R-versioner. Besök go/r-bg-fgs-restriction och skicka en felrapport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vill du höja volymen över den rekommenderade nivån?\n\nAtt lyssna med stark volym långa stunder åt gången kan skada hörseln."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vill du använda Aktivera tillgänglighet snabbt?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Redigera genvägar"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Avbryt"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Inaktivera kortkommandot"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Okategoriserad"</string> <string name="importance_from_user" msgid="2782756722448800447">"Du anger hur viktiga aviseringarna är."</string> <string name="importance_from_person" msgid="4235804979664465383">"Detta är viktigt på grund av personerna som deltar."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g> (det finns redan en användare med det här kontot)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Lägg till ett språk"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Det går inte att dela med jobbappar"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Det går inte att dela med personliga appar"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"IT-administratören har blockerat delning mellan personliga och jobbappar"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Aktivera jobbappar"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Aktivera jobbappar om du vill få åtkomst till jobbrelaterade appar och kontakter"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Det finns inga tillgängliga appar"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Vi hittade inga appar"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Aktivera jobbprofil"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Spela in och spela upp ljud i telefonsamtal"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Tillåter appen att spela in och spela upp ljud i telefonsamtal när den har angetts som standardapp för uppringningsfunktionen."</string> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index e94856bb1f53..5ef601fba163 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Shirika lako linadhibiti kifaa hiki na huenda likafuatilia shughuli kwenye mtandao. Gusa ili upate maelezo zaidi."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Mipangilio ya mahali imebadilishwa na msimamizi wako"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Gusa ili uone mipangilio ya mahali ulipo."</string> + <string name="country_detector" msgid="7023275114706088854">"Kitambuzi cha Nchi"</string> + <string name="location_service" msgid="2439187616018455546">"Huduma ya Mahali"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Huduma ya Arifa ya Kitambuzi"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="other">Inapiga picha ya skrini ili iripoti hitilafu baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>.</item> <item quantity="one">Inapiga picha ya skrini ili iripoti hitilafu baada ya sekunde <xliff:g id="NUMBER_0">%d</xliff:g>.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Mtindo wa kimya"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Sauti Imezimwa"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Sauti imewashwa"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Jaribu tena."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hakuna alama za vidole zilizojumuishwa."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Kitambuzi kimezimwa kwa muda."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Kidole cha <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Imeshindwa kuthibitisha uso. Jaribu tena."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Hujaweka mipangilio ya kufungua kwa uso."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Kufungua kwa uso hakutumiki kwenye kifaa hiki."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Kitambuzi kimezimwa kwa muda."</string> <string name="face_name_template" msgid="3877037340223318119">"Uso wa <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Utatuzi wa USB umeunganishwa"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Gusa ili uzime utatuzi wa USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Chagua ili kulemaza utatuaji USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Umeunganisha utatuzi usiotumia waya"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Gusa ili uzime utatuzi usiotumia waya"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Chagua ili uzime utatuzi usiotumia waya."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Hali ya Muunganisho wa Majaribio imewashwa"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Rejesha mipangilio iliyotoka nayo kiwandani ili uzime hali ya Muunganisho wa Majaribio."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Muunganisho kupitia mlango umewashwa"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Huduma ya programu inayotumika iliyoanzishwa chinichini kwenye <xliff:g id="PACKAGENAME">%1$s</xliff:g> haitakuwa na ruhusa inapotumika katika miundo ijayo ya R. Tafadhali angalia go/r-bg-fgs-restriction na uwasilishe ripoti ya hitilafu."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ungependa kutumia njia ya mkato ya ufikivu?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa sekunde tatu itafungua kipengele cha ufikivu."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kubadilisha njia za mkato"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Ghairi"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Zima kipengele cha Njia ya Mkato"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Ambazo aina haijabainishwa"</string> <string name="importance_from_user" msgid="2782756722448800447">"Uliweka mipangilio ya umuhimu wa arifa hizi."</string> <string name="importance_from_person" msgid="4235804979664465383">"Hii ni muhimu kwa sababu ya watu waliohusika."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Ruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g> (Je, tayari kuna mtumiaji anayetumia akaunti hii)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Ongeza lugha"</string> @@ -1917,7 +1927,7 @@ <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Ungependa kusasisha <xliff:g id="TYPE_0">%1$s</xliff:g> na <xliff:g id="TYPE_1">%2$s</xliff:g> katika "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string> <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"Ungependa kusasisha vipengee hivi katika "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> na <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string> <string name="autofill_save_yes" msgid="8035743017382012850">"Hifadhi"</string> - <string name="autofill_save_no" msgid="9212826374207023544">"Hapana, asante"</string> + <string name="autofill_save_no" msgid="9212826374207023544">"Hapana"</string> <string name="autofill_save_notnow" msgid="2853932672029024195">"Si sasa"</string> <string name="autofill_save_never" msgid="6821841919831402526">"Kamwe"</string> <string name="autofill_update_yes" msgid="4608662968996874445">"Sasisha"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Binafsi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Kazini"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Imeshindwa kushiriki na programu za kazini"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Imeshindwa kushiriki na programu za binafsi"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Msimamizi wako wa TEHAMA amezuia kushiriki kati ya programu za binafsi na za kazini"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Washa programu za kazini"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Washa programu za kazini ili ufikie programu na anwani za kazini"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Hakuna programu zinazopatikana"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Hatujapata programu zozote"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Washa wasifu wa kazini"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Kurekodi au kucheza sauti katika simu"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Huruhusu programu hii, wakati imekabidhiwa kuwa programu chaguomsingi ya kipiga simu, kurekodi au kucheza sauti katika simu."</string> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 8245786b7216..da6cf4b643f3 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -191,9 +191,15 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"நிர்வாகியால் தனிப்பட்ட உபயோகத்திற்காக ஒதுக்கப்பட்ட சாதனம்"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"சாதனம் நிர்வகிக்கப்படுகிறது"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"உங்கள் நிறுவனம் இந்தச் சாதனத்தை நிர்வகிக்கும், அத்துடன் அது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கலாம். விவரங்களுக்கு, தட்டவும்."</string> - <!-- no translation found for location_changed_notification_title (4119726617105166830) --> + <string name="location_changed_notification_title" msgid="4119726617105166830">"உங்கள் நிர்வாகியால் இருப்பிட அமைப்புகள் மாற்றப்பட்டன"</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"உங்கள் இருப்பிட அமைப்புகளைப் பார்க்க தட்டவும்."</string> + <!-- no translation found for country_detector (7023275114706088854) --> <skip /> - <!-- no translation found for location_changed_notification_text (198907268219396399) --> + <!-- no translation found for location_service (2439187616018455546) --> + <skip /> + <!-- no translation found for sensor_notification_service (7474531979178682676) --> + <skip /> + <!-- no translation found for twilight_service (8964898045693187224) --> <skip /> <string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string> <string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string> @@ -247,6 +253,10 @@ <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகளில் பிழை அறிக்கைக்கான ஸ்கிரீன்ஷாட் எடுக்கப்படும்.</item> <item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> வினாடியில் பிழை அறிக்கைக்கான ஸ்கிரீன்ஷாட் எடுக்கப்படும்.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"நிசப்த பயன்முறை"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ஒலி முடக்கத்தில் உள்ளது"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ஒலி இயக்கத்தில் உள்ளது"</string> @@ -375,7 +385,7 @@ <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"நினைவகத்தில் நிலையாக இருக்கும் தன்னுடைய பகுதிகளை உருவாக்கப் ஆப்ஸை அனுமதிக்கிறது. இதனால பிற பயன்பாடுகளுக்குக் கிடைக்கும் நினைவகம் வரையறுக்கப்பட்டு, மொபைலின் வேகத்தைக் குறைக்கலாம்"</string> <string name="permlab_foregroundService" msgid="1768855976818467491">"முன்புலத்தில் இயங்கும் சேவையை இயக்குதல்"</string> <string name="permdesc_foregroundService" msgid="8720071450020922795">"முன்புலத்தில் இயங்கும் சேவைகளை உபயோகிக்க, ஆப்ஸை அனுமதிக்கிறது."</string> - <string name="permlab_getPackageSize" msgid="375391550792886641">"பயன்பாட்டுச் சேமிப்பு இடத்தை அளவிடல்"</string> + <string name="permlab_getPackageSize" msgid="375391550792886641">"ஆப்ஸ் சேமிப்பு இடத்தை அளவிடல்"</string> <string name="permdesc_getPackageSize" msgid="742743530909966782">"ஆப்ஸ், அதன் குறியீடு, தரவு, மற்றும் தற்காலிகச் சேமிப்பு அளவுகளை மீட்டெடுக்க அனுமதிக்கிறது"</string> <string name="permlab_writeSettings" msgid="8057285063719277394">"சாதன அமைப்புகளை மாற்றுதல்"</string> <string name="permdesc_writeSettings" msgid="8293047411196067188">"முறைமையின் அமைப்பு தரவைத் திருத்த, ஆப்ஸை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் ஆப்ஸ், முறைமையின் உள்ளமைவைச் சிதைக்கலாம்."</string> @@ -433,8 +443,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"இந்த முன்னுரிமை பெற்ற சிஸ்டம் ஆப்ஸால் சிஸ்டம் கேமராவைப் பயன்படுத்தி எப்போது வேண்டுமானாலும் படங்களை எடுக்கவோ வீடியோக்களை ரெக்கார்டு செய்யவோ முடியும். android.permission.CAMERA அனுமதியும் ஆப்ஸிற்குத் தேவை"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"அதிர்வைக் கட்டுப்படுத்துதல்"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"அதிர்வைக் கட்டுப்படுத்தப் ஆப்ஸை அனுமதிக்கிறது."</string> - <!-- no translation found for permdesc_vibrator_state (7050024956594170724) --> - <skip /> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"அதிர்வு நிலையை அணுக ஆப்ஸை அனுமதிக்கும்."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் ஆப்ஸை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது ஆப்ஸை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் ஆப்ஸ், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS அழைப்புச் சேவையை அணுகுதல்"</string> @@ -474,7 +483,7 @@ <string name="permlab_accessNetworkState" msgid="2349126720783633918">"நெட்வொர்க் இணைப்புகளைக் காட்டு"</string> <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"தற்போது இருக்கும் நெட்வொர்க்குகள் எவை மற்றும் இணைக்கப்பட்டுள்ளவை எவை போன்ற நெட்வொர்க் இணைப்புகள் குறித்த தகவலைப் பார்க்கப் ஆப்ஸை அனுமதிக்கிறது."</string> <string name="permlab_createNetworkSockets" msgid="3224420491603590541">"முழுமையான நெட்வொர்க் அணுகலைக் கொண்டிருக்கும்"</string> - <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"நெட்வொர்க் சாக்கெட்டுகளை உருவாக்கவும் மற்றும் தனிப்பயன் நெட்வொர்க் நெறிமுறைகளைப் பயன்படுத்தவும் ஆப்ஸை அனுமதிக்கிறது. இணையத்தில் தரவை அனுப்ப உலாவியும், பிற பயன்பாடுகளும் இருப்பதால், இணையத்திற்குத் தரவை அனுப்ப இந்த அனுமதி தேவையில்லை."</string> + <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"நெட்வொர்க் சாக்கெட்டுகளை உருவாக்கவும் மற்றும் பிரத்தியேக நெட்வொர்க் நெறிமுறைகளைப் பயன்படுத்தவும் ஆப்ஸை அனுமதிக்கிறது. இணையத்தில் தரவை அனுப்ப உலாவியும், பிற பயன்பாடுகளும் இருப்பதால், இணையத்திற்குத் தரவை அனுப்ப இந்த அனுமதி தேவையில்லை."</string> <string name="permlab_changeNetworkState" msgid="8945711637530425586">"பிணைய இணைப்புத்தன்மையை மாற்றுதல்"</string> <string name="permdesc_changeNetworkState" msgid="649341947816898736">"நெட்வொர்க் இணைப்பின் நிலையை மாற்ற, ஆப்ஸை அனுமதிக்கிறது."</string> <string name="permlab_changeTetherState" msgid="9079611809931863861">"இணைக்கப்பட்ட இணைப்புநிலையை மாற்றுதல்"</string> @@ -697,30 +706,30 @@ <item msgid="4537253139152229577">"வீட்டு தொலைநகல்"</item> <item msgid="6751245029698664340">"பேஜர்"</item> <item msgid="1692790665884224905">"மற்றவை"</item> - <item msgid="6216981255272016212">"தனிப்பயன்"</item> + <item msgid="6216981255272016212">"பிரத்தியேகம்"</item> </string-array> <string-array name="emailAddressTypes"> <item msgid="7786349763648997741">"வீடு"</item> <item msgid="435564470865989199">"அலுவலகம்"</item> <item msgid="4199433197875490373">"மற்றவை"</item> - <item msgid="3233938986670468328">"தனிப்பயன்"</item> + <item msgid="3233938986670468328">"பிரத்தியேகம்"</item> </string-array> <string-array name="postalAddressTypes"> <item msgid="3861463339764243038">"வீடு"</item> <item msgid="5472578890164979109">"அலுவலகம்"</item> <item msgid="5718921296646594739">"மற்றவை"</item> - <item msgid="5523122236731783179">"தனிப்பயன்"</item> + <item msgid="5523122236731783179">"பிரத்தியேகம்"</item> </string-array> <string-array name="imAddressTypes"> <item msgid="588088543406993772">"வீடு"</item> <item msgid="5503060422020476757">"அலுவலகம்"</item> <item msgid="2530391194653760297">"மற்றவை"</item> - <item msgid="7640927178025203330">"தனிப்பயன்"</item> + <item msgid="7640927178025203330">"பிரத்தியேகம்"</item> </string-array> <string-array name="organizationTypes"> <item msgid="6144047813304847762">"அலுவலகம்"</item> <item msgid="7402720230065674193">"மற்றவை"</item> - <item msgid="808230403067569648">"தனிப்பயன்"</item> + <item msgid="808230403067569648">"பிரத்தியேகம்"</item> </string-array> <string-array name="imProtocols"> <item msgid="7535761744432206400">"AIM"</item> @@ -732,7 +741,7 @@ <item msgid="4717545739447438044">"ICQ"</item> <item msgid="8293711853624033835">"Jabber"</item> </string-array> - <string name="phoneTypeCustom" msgid="5120365721260686814">"தனிப்பயன்"</string> + <string name="phoneTypeCustom" msgid="5120365721260686814">"பிரத்தியேகம்"</string> <string name="phoneTypeHome" msgid="3880132427643623588">"வீடு"</string> <string name="phoneTypeMobile" msgid="1178852541462086735">"மொபைல்"</string> <string name="phoneTypeWork" msgid="6604967163358864607">"அலுவலகம்"</string> @@ -753,24 +762,24 @@ <string name="phoneTypeWorkPager" msgid="3748332310638505234">"பணியிட பேஜர்"</string> <string name="phoneTypeAssistant" msgid="757550783842231039">"உதவியாளர்"</string> <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string> - <string name="eventTypeCustom" msgid="3257367158986466481">"தனிப்பயன்"</string> + <string name="eventTypeCustom" msgid="3257367158986466481">"பிரத்தியேகம்"</string> <string name="eventTypeBirthday" msgid="7770026752793912283">"பிறந்தநாள்"</string> <string name="eventTypeAnniversary" msgid="4684702412407916888">"ஆண்டுவிழா"</string> <string name="eventTypeOther" msgid="530671238533887997">"மற்றவை"</string> - <string name="emailTypeCustom" msgid="1809435350482181786">"தனிப்பயன்"</string> + <string name="emailTypeCustom" msgid="1809435350482181786">"பிரத்தியேகம்"</string> <string name="emailTypeHome" msgid="1597116303154775999">"வீடு"</string> <string name="emailTypeWork" msgid="2020095414401882111">"அலுவலகம்"</string> <string name="emailTypeOther" msgid="5131130857030897465">"மற்றவை"</string> <string name="emailTypeMobile" msgid="787155077375364230">"மொபைல்"</string> - <string name="postalTypeCustom" msgid="5645590470242939129">"தனிப்பயன்"</string> + <string name="postalTypeCustom" msgid="5645590470242939129">"பிரத்தியேகம்"</string> <string name="postalTypeHome" msgid="7562272480949727912">"வீடு"</string> <string name="postalTypeWork" msgid="8553425424652012826">"அலுவலகம்"</string> <string name="postalTypeOther" msgid="7094245413678857420">"மற்றவை"</string> - <string name="imTypeCustom" msgid="5653384545085765570">"தனிப்பயன்"</string> + <string name="imTypeCustom" msgid="5653384545085765570">"பிரத்தியேகம்"</string> <string name="imTypeHome" msgid="6996507981044278216">"வீடு"</string> <string name="imTypeWork" msgid="2099668940169903123">"அலுவலகம்"</string> <string name="imTypeOther" msgid="8068447383276219810">"மற்றவை"</string> - <string name="imProtocolCustom" msgid="4437878287653764692">"தனிப்பயன்"</string> + <string name="imProtocolCustom" msgid="4437878287653764692">"பிரத்தியேகம்"</string> <string name="imProtocolAim" msgid="4050198236506604378">"AIM"</string> <string name="imProtocolMsn" msgid="2257148557766499232">"Windows Live"</string> <string name="imProtocolYahoo" msgid="5373338758093392231">"Yahoo"</string> @@ -782,8 +791,8 @@ <string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string> <string name="orgTypeWork" msgid="8684458700669564172">"அலுவலகம்"</string> <string name="orgTypeOther" msgid="5450675258408005553">"மற்றவை"</string> - <string name="orgTypeCustom" msgid="1126322047677329218">"தனிப்பயன்"</string> - <string name="relationTypeCustom" msgid="282938315217441351">"தனிப்பயன்"</string> + <string name="orgTypeCustom" msgid="1126322047677329218">"பிரத்தியேகம்"</string> + <string name="relationTypeCustom" msgid="282938315217441351">"பிரத்தியேகம்"</string> <string name="relationTypeAssistant" msgid="4057605157116589315">"உதவியாளர்"</string> <string name="relationTypeBrother" msgid="7141662427379247820">"சகோதரர்"</string> <string name="relationTypeChild" msgid="9076258911292693601">"குழந்தை"</string> @@ -798,7 +807,7 @@ <string name="relationTypeRelative" msgid="3396498519818009134">"உறவினர்"</string> <string name="relationTypeSister" msgid="3721676005094140671">"சகோதரி"</string> <string name="relationTypeSpouse" msgid="6916682664436031703">"துணைவர்"</string> - <string name="sipAddressTypeCustom" msgid="6283889809842649336">"தனிப்பயன்"</string> + <string name="sipAddressTypeCustom" msgid="6283889809842649336">"பிரத்தியேகம்"</string> <string name="sipAddressTypeHome" msgid="5918441930656878367">"வீடு"</string> <string name="sipAddressTypeWork" msgid="7873967986701216770">"அலுவலகம்"</string> <string name="sipAddressTypeOther" msgid="6317012577345187275">"மற்றவை"</string> @@ -833,8 +842,8 @@ <string name="lockscreen_missing_sim_instructions_long" msgid="3664999892038416334">"சிம் கார்டு இல்லை அல்லது படிக்கக்கூடியதாக இல்லை. சிம் கார்டைச் செருகவும்."</string> <string name="lockscreen_permanent_disabled_sim_message_short" msgid="3812893366715730539">"பயன்படுத்த முடியாத சிம் கார்டு."</string> <string name="lockscreen_permanent_disabled_sim_instructions" msgid="4358929052509450807">"உங்கள் சிம் கார்டு நிரந்தரமாக முடக்கப்பட்டது.\n மற்றொரு சிம் கார்டிற்காக உங்கள் வயர்லெஸ் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்."</string> - <string name="lockscreen_transport_prev_description" msgid="2879469521751181478">"முந்தைய ட்ராக்"</string> - <string name="lockscreen_transport_next_description" msgid="2931509904881099919">"அடுத்த ட்ராக்"</string> + <string name="lockscreen_transport_prev_description" msgid="2879469521751181478">"முந்தைய டிராக்"</string> + <string name="lockscreen_transport_next_description" msgid="2931509904881099919">"அடுத்த டிராக்"</string> <string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"இடைநிறுத்து"</string> <string name="lockscreen_transport_play_description" msgid="106868788691652733">"இயக்கு"</string> <string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"நிறுத்து"</string> @@ -1321,6 +1330,12 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB பிழைதிருத்தத்தை முடக்க, தேர்ந்தெடுக்கவும்."</string> + <!-- no translation found for adbwifi_active_notification_title (6147343659168302473) --> + <skip /> + <!-- no translation found for adbwifi_active_notification_message (930987922852867972) --> + <skip /> + <!-- no translation found for adbwifi_active_notification_message (8633421848366915478) --> + <skip /> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"\'தன்னியக்க சோதனைப்\' பயன்முறை இயக்கப்பட்டது"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"’தன்னியக்க சோதனைப்\' பயன்முறையை முடக்க ஆரம்பநிலைக்கு மீட்டமைக்கவும்."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"சீரியல் கன்சோல் இயக்கப்பட்டது"</string> @@ -1848,6 +1863,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"வகைப்படுத்தப்படாதவை"</string> <string name="importance_from_user" msgid="2782756722448800447">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string> <string name="importance_from_person" msgid="4235804979664465383">"ஈடுபட்டுள்ளவர்களின் காரணமாக, இது முக்கியமானது."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா (இந்தக் கணக்கில் ஏற்கெனவே ஒரு பயனர் உள்ளார்) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string> <string name="language_selection_title" msgid="52674936078683285">"மொழியைச் சேர்"</string> @@ -1951,7 +1968,7 @@ <string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string> <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"ஆப்ஸ் முந்தையப் பதிப்பிற்கு மாற்றப்பட்டது, அல்லது இந்த ஷார்ட்கட் வேலை செய்யவில்லை"</string> <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"காப்புப் பிரதி மற்றும் மீட்டமைவைப் ஆப்ஸ் ஆதரிக்காத காரணத்தால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string> - <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"பயன்பாட்டுச் சான்றுகள் பொருந்தாத காரணத்தினால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string> + <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"ஆப்ஸ் சான்றுகள் பொருந்தாத காரணத்தினால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string> <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை"</string> <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"ஷார்ட்கட் முடக்கப்பட்டுள்ளது"</string> <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"நிறுவல் நீக்கு"</string> @@ -2037,4 +2054,8 @@ <skip /> <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> <skip /> + <!-- no translation found for permlab_accessCallAudio (1682957511874097664) --> + <skip /> + <!-- no translation found for permdesc_accessCallAudio (8448360894684277823) --> + <skip /> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 7d01f585b0ab..f6cc17e314f2 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -192,7 +192,11 @@ <string name="network_logging_notification_title" msgid="554983187553845004">"పరికరం నిర్వహించబడింది"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"మీ సంస్థ ఈ పరికరాన్ని నిర్వహిస్తుంది మరియు నెట్వర్క్ ట్రాఫిక్ని పర్యవేక్షించవచ్చు. వివరాల కోసం నొక్కండి."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"మీ అడ్మిన్ లొకేషన్ సెట్టింగ్లను మార్చారు"</string> - <string name="location_changed_notification_text" msgid="198907268219396399">"మీ లొకేషన్ సెట్టింగ్లను చుడటానికి ట్యాప్ చేయండి."</string> + <string name="location_changed_notification_text" msgid="198907268219396399">"మీ లొకేషన్ సెట్టింగ్లను చూడటానికి ట్యాప్ చేయండి."</string> + <string name="country_detector" msgid="7023275114706088854">"దేశం డిటెక్టర్"</string> + <string name="location_service" msgid="2439187616018455546">"లొకేషన్ సర్వీస్"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"సెన్సార్ నోటిఫికేషన్ సర్వీస్"</string> + <string name="twilight_service" msgid="8964898045693187224">"ట్విలైట్ సర్వీస్"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string> <string name="factory_reset_message" msgid="2657049595153992213">"నిర్వాహక యాప్ ఉపయోగించడం సాధ్యపడదు. మీ పరికరంలోని డేటా ఇప్పుడు తొలగించబడుతుంది.\n\nమీకు ప్రశ్నలు ఉంటే, మీ సంస్థ యొక్క నిర్వాహకులను సంప్రదించండి."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"ముద్రణ <xliff:g id="OWNER_APP">%s</xliff:g> ద్వారా నిలిపివేయబడింది."</string> @@ -245,6 +249,10 @@ <item quantity="other">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో స్క్రీన్షాట్ తీయబోతోంది.</item> <item quantity="one">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_0">%d</xliff:g> సెకనులో స్క్రీన్షాట్ తీయబోతోంది.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"నిశ్శబ్ద మోడ్"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ధ్వని ఆఫ్లో ఉంది"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ధ్వని ఆన్లో ఉంది"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"మళ్లీ ప్రయత్నించండి."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"వేలిముద్రలు నమోదు చేయబడలేదు."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"వేలు <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"ముఖం ధృవీకరించలేకపోయింది. మళ్లీ ప్రయత్నించండి."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"మీరు ముఖంతో అన్లాక్ను సెటప్ చేయలేదు."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"ఈ పరికరంలో ముఖంతో అన్లాక్ను ఉపయోగించడానికి మద్దతు లేదు."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string> <string name="face_name_template" msgid="3877037340223318119">"ముఖ <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB డీబగ్గింగ్ను ఆఫ్ చేయడానికి నొక్కండి"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"డీబగ్గింగ్ని నిలిపివేయడానికి ఎంచుకోండి."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"వైర్లెస్ డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"వైర్లెస్ డీబగ్గింగ్ని ఆఫ్ చేయడానికి ట్యాప్ చేయండి"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"వైర్లెస్ డీబగ్గింగ్ని డిజేబుల్ చేయడానికి ఎంచుకోండి."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"పరీక్ష నియంత్రణ మోడ్ ప్రారంభించబడింది"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"పరీక్ష నియంత్రణ మోడ్ను నిలిపివేయడానికి ఫ్యాక్టరీ రీసెట్ను అమలు చేయండి."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"సీరియల్ కన్సోల్ ప్రారంభించబడింది"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> నుండి, బ్యాక్గ్రౌండ్లో ప్రారంభమైన ఫోర్ గ్రౌండ్ సేవకు భవిష్యత్తు R బిల్డ్స్లో \'ఉపయోగంలో వున్నప్పుడు\' అనుమతి ఉండదు. దయచేసి go/r-bg-fgs-restrictionను చూసి బగ్ నివేదికను ఫైల్ చేయండి."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"వాల్యూమ్ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"యాక్సెస్ సామర్థ్యం షార్ట్కట్ను ఉపయోగించాలా?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"షార్ట్కట్ ఆన్ చేసి ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్లను 3 సెకన్ల పాటు నొక్కి ఉంచితే యాక్సెస్ సౌలభ్య ఫీచర్ ప్రారంభం అవుతుంది."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"షార్ట్కట్లను ఎడిట్ చేయి"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"రద్దు చేయి"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"సత్వరమార్గాన్ని ఆఫ్ చేయి"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"వర్గీకరించబడలేదు"</string> <string name="importance_from_user" msgid="2782756722448800447">"మీరు ఈ నోటిఫికేషన్ల ప్రాముఖ్యతను సెట్ చేసారు."</string> <string name="importance_from_person" msgid="4235804979664465383">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా (ఈ ఖాతాతో ఇప్పటికే ఒక వినియోగదారు ఉన్నారు) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా?"</string> <string name="language_selection_title" msgid="52674936078683285">"భాషను జోడించండి"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"వ్యక్తిగతం"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"కార్యాలయం"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"వర్క్ యాప్లతో షేర్ చేయడం సాధ్యపడదు"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"వ్యక్తిగత యాప్లతో షేర్ చేయడం సాధ్యపడదు"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"వ్యక్తిగత, వర్క్ యాప్ల మధ్య షేర్ చేయడాన్ని మీ IT అడ్మిన్ బ్లాక్ చేశారు"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"వర్క్ యాప్లను ఆన్ చేయండి"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"వర్క్ యాప్లు & కాంటాక్ట్లను యాక్సెస్ చేయడానికి వర్క్ యాప్లను ఆన్ చేయండి"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"యాప్లు ఏవీ అందుబాటులో లేవు"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"మేము యాప్లు వేటినీ కనుగొనలేకపోయాము"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"కార్యాలయ ప్రొఫైల్ను ఆన్ చేయి"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"టెలిఫోనీ కాల్స్లో రికార్డ్ చేయండి లేదా ఆడియో ప్లే చేయండి"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"డిఫాల్ట్ డయలర్ యాప్గా కేటాయించినప్పుడు, టెలిఫోనీ కాల్స్లో రికార్డ్ చేయడానికి లేదా ఆడియో ప్లే చేయడానికి ఈ యాప్ను అనుమతిస్తుంది."</string> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 7f966db9fd2c..90831d71f1d1 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -191,8 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"ผู้ดูแลระบบปล่อยอุปกรณ์ให้คุณใช้งานส่วนตัว"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"อุปกรณ์มีการจัดการ"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"องค์กรของคุณจัดการอุปกรณ์นี้และอาจตรวจสอบการจราจรของข้อมูลในเครือข่าย แตะเพื่อดูรายละเอียด"</string> - <string name="location_changed_notification_title" msgid="4119726617105166830">"ผู้ดูแลระบบได้เปลี่ยนการตั้งค่าตำแหน่ง"</string> + <string name="location_changed_notification_title" msgid="4119726617105166830">"ผู้ดูแลระบบเปลี่ยนการตั้งค่าตำแหน่ง"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"แตะเพื่อดูการตั้งค่าตำแหน่ง"</string> + <string name="country_detector" msgid="7023275114706088854">"เครื่องมือหาตำแหน่งประเทศ"</string> + <string name="location_service" msgid="2439187616018455546">"บริการตำแหน่ง"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"บริการแจ้งเตือนเกี่ยวกับเซ็นเซอร์"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight Service"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string> <string name="factory_reset_message" msgid="2657049595153992213">"ใช้แอปผู้ดูแลระบบนี้ไม่ได้ ขณะนี้ระบบจะลบข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบขององค์กรหากมีคำถาม"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ปิดใช้การพิมพ์แล้ว"</string> @@ -245,6 +249,10 @@ <item quantity="other">จะจับภาพหน้าจอสำหรับรายงานข้อบกพร่องใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที</item> <item quantity="one">จะจับภาพหน้าจอสำหรับรายงานข้อบกพร่องใน <xliff:g id="NUMBER_0">%d</xliff:g> วินาที</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"โหมดปิดเสียง"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ปิดเสียงไว้"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"เปิดเสียงแล้ว"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"ลองอีกครั้ง"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ไม่มีลายนิ้วมือที่ลงทะเบียน"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"ยืนยันใบหน้าไม่ได้ ลองอีกครั้ง"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"คุณยังไม่ได้ตั้งค่า Face Unlock"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับ Face Unlock"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> <string name="face_name_template" msgid="3877037340223318119">"ใบหน้า <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"แตะเพื่อปิดการแก้ไขข้อบกพร่อง USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"เลือกเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"เชื่อมต่อการแก้ไขข้อบกพร่องผ่าน Wi-Fi"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"แตะเพื่อปิดการแก้ไขข้อบกพร่องผ่าน Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"เลือกเพื่อปิดใช้การแก้ไขข้อบกพร่องผ่าน Wi-Fi"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"โหมดโปรแกรมทดสอบอัตโนมัติเปิดใช้อยู่"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"รีเซ็ตเป็นค่าเริ่มต้นเพื่อปิดใช้โหมดโปรแกรมทดสอบอัตโนมัติ"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"เปิดใช้คอนโซลการเรียงอันดับแล้ว"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"บริการที่ทำงานอยู่เบื้องหน้าซึ่งเริ่มขึ้นในเบื้องหลังจาก <xliff:g id="PACKAGENAME">%1$s</xliff:g> จะไม่มีสิทธิ์ขณะใช้งานใน R บิลด์ต่อๆ ไป โปรดดู go/r-bg-fgs-restriction และส่งรายงานข้อบกพร่อง"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"นี่เป็นการเพิ่มระดับเสียงเกินระดับที่แนะนำ\n\nการฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ใช้ทางลัดการช่วยเหลือพิเศษไหม"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มนาน 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"แก้ไขทางลัด"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"ยกเลิก"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ปิดทางลัด"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"ไม่จัดอยู่ในหมวดหมู่ใดๆ"</string> <string name="importance_from_user" msgid="2782756722448800447">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string> <string name="importance_from_person" msgid="4235804979664465383">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม (มีผู้ใช้ที่มีบัญชีนี้อยู่แล้ว)"</string> <string name="user_creation_adding" msgid="7305185499667958364">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string> <string name="language_selection_title" msgid="52674936078683285">"เพิ่มภาษา"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนตัว"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"งาน"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"แชร์ด้วยแอปงานไม่ได้"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"แชร์ด้วยแอปส่วนตัวไม่ได้"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"ผู้ดูแลระบบไอทีบล็อกการแชร์ระหว่างแอปส่วนตัวและแอปงาน"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"เปิดแอปงาน"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"เปิดแอปงานเพื่อเข้าถึงแอปงานและรายชื่อติดต่อ"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"ไม่มีแอป"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"เราไม่พบแอปใดเลย"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"เปิดโปรไฟล์งาน"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"บันทึกหรือเปิดเสียงในสายโทรศัพท์"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"อนุญาตให้แอปนี้ (เมื่อกำหนดให้เป็นแอปโทรออกเริ่มต้น) บันทึกหรือเปิดเสียงในสายโทรศัพท์ได้"</string> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 53818ed7ba6a..d65c2147251f 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Pinamamahalaan ng iyong organisasyon ang device na ito, at maaari nitong subaybayan ang trapiko sa network. I-tap para sa mga detalye."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Binago ang mga setting ng lokasyon ng iyong admin"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"I-tap para makita ang iyong mga setting ng lokasyon."</string> + <string name="country_detector" msgid="7023275114706088854">"Detector ng Bansa"</string> + <string name="location_service" msgid="2439187616018455546">"Serbisyo ng Lokasyon"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Serbisyo ng Notification ng Sensor"</string> + <string name="twilight_service" msgid="8964898045693187224">"Serbisyo ng Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Hindi magamit ang admin app. Mabubura na ang iyong device.\n\nKung mayroon kang mga tanong, makipag-ugnayan sa admin ng iyong organisasyon."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Na-disable ng <xliff:g id="OWNER_APP">%s</xliff:g> ang pag-print."</string> @@ -245,6 +249,10 @@ <item quantity="one">Kukuha ng screenshot para sa ulat ng bug sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> segundo.</item> <item quantity="other">Kukuha ng screenshot para sa ulat ng bug sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> na segundo.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Silent mode"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Naka-OFF ang tunog"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Naka-ON ang sound"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Subukang muli."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Walang naka-enroll na fingerprint."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Pansamantalang na-disable ang sensor."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Hindi ma-verify ang mukha. Subukang muli."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Hindi mo pa nase-set up ang face unlock."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Hindi sinusuportahan ang face unlock sa device na ito."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Pansamantalang na-disable ang sensor."</string> <string name="face_name_template" msgid="3877037340223318119">"Mukha <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Nakakonekta ang pag-debug ng USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"I-tap para i-off ang pag-debug ng USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Piliin upang i-disable ang debugging ng USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Nakakonekta ang wireless na pag-debug"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"I-tap para i-off ang wireless na pag-debug"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Piliin para i-disable ang wireless na pag-debug."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Naka-enable ang Test Harness Mode"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Mag-factory reset para i-disable ang Test Harness Mode."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Naka-enable ang serial console"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ang sinimulan sa background na serbisyo sa foreground mula sa <xliff:g id="PACKAGENAME">%1$s</xliff:g> ay hindi magkakaroon ng pahintulot habang ginagamit sa mga R build sa hinaharap. Pakipuntahan ang go/r-bg-fgs-restriction at maghain ng bugreport."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Pagiging Accessible?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"I-edit ang mga shortcut"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Kanselahin"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"I-off ang Shortcut"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Di-nakategorya"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ikaw ang magtatakda sa kahalagahan ng mga notification na ito."</string> <string name="importance_from_person" msgid="4235804979664465383">"Mahalaga ito dahil sa mga taong kasangkot."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> (mayroon nang User sa account na ito) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Magdagdag ng wika"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabaho"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Hindi puwedeng magbahagi sa mga app para sa trabaho"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Hindi puwedeng magbahagi sa mga personal na app"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Na-block ng iyong IT admin ang pagbabahagi sa pagitan ng mga personal na app at app para sa trabaho"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"I-on ang mga app para sa trabaho"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"I-on ang mga app para sa trabaho para ma-access ang mga app at contact para sa trabaho"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Walang available na app"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Wala kaming makitang anumang app"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"I-on ang pantrabahong profile"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Mag-record o mag-play ng audio sa mga tawag sa telephony"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Papayagan ang app na ito na mag-record o mag-play ng audio sa mga tawag sa telephony kapag naitalaga bilang default na dialer application."</string> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 2e3bf3af7dbf..718df3d72f8e 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Kuruluşunuz bu cihazı yönetmekte olup ağ trafiğini izleyebilir. Ayrıntılar için dokunun."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Konum ayarları, yöneticiniz tarafından değiştirildi"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Konum ayarlarınızı görmek için dokunun."</string> + <string name="country_detector" msgid="7023275114706088854">"Ülke Algılayıcı"</string> + <string name="location_service" msgid="2439187616018455546">"Konum Hizmeti"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensör Bildirim Hizmeti"</string> + <string name="twilight_service" msgid="8964898045693187224">"Alacakaranlık Hizmeti"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Yönetim uygulaması kullanılamıyor. Cihazınız şimdi silinecek.\n\nSorularınız varsa kuruluşunuzun yöneticisine başvurun."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Yazdırma işlemi <xliff:g id="OWNER_APP">%s</xliff:g> tarafından devre dışı bırakıldı."</string> @@ -245,6 +249,10 @@ <item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde hata raporu ekran görüntüsü alınıyor.</item> <item quantity="one">Hata raporu ekran görüntüsü <xliff:g id="NUMBER_0">%d</xliff:g> saniye içinde alınacak.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Sessiz mod"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Ses KAPALI"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Ses AÇIK"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Tekrar deneyin."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Parmak izi kaydedilmedi."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensör geçici olarak devre dışı bırakıldı."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Yüz doğrulanamıyor. Tekrar deneyin."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Yüz tanıma kilidi ayarlamadınız."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Bu cihazda yüz tanıma kilidi desteklenmiyor"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensör geçici olarak devre dışı bırakıldı."</string> <string name="face_name_template" msgid="3877037340223318119">"Yüz <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB hata ayıklaması bağlandı"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB hata ayıklama işlevini kapatmak için dokunun"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB hata ayıklamasını devre dışı bırakmak için seçin."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Kablosuz hata ayıklama bağlı"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Kablosuz hata ayıklamayı kapatmak için dokunun"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Kablosuz hata ayıklamayı devre dışı bırakmak için seçin."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Bandı Modu etkin"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Test Bandı Modu\'nu devre dışı bırakmak için cihazı fabrika ayarlarına sıfırlayın."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Seri konsol etkinleştirildi"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> paketinden ön plan hizmetini başlatan arka plan, sonraki R derlemelerinde kullanım sırasında iznine sahip olmayacak. Lütfen go/r-bg-fgs-restriction sayfasına bakıp hata raporu girin."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ses seviyesi önerilen düzeyin üzerine yükseltilsin mi?\n\nUzun süre yüksek ses seviyesinde dinlemek işitme duyunuza zarar verebilir."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erişilebilirlik Kısayolu Kullanılsın mı?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kısayol açıkken ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Kısayolları düzenle"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"İptal"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Kısayolu Kapat"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Kategorize edilmemiş"</string> <string name="importance_from_user" msgid="2782756722448800447">"Bu bildirimlerin önem derecesini ayarladınız."</string> <string name="importance_from_person" msgid="4235804979664465383">"Bu, dahil olan kişiler nedeniyle önemlidir."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi (bu hesaba sahip bir kullanıcı zaten var)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string> <string name="language_selection_title" msgid="52674936078683285">"Dil ekleyin"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Kişisel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"İş uygulamalarıyla paylaşılamıyor"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kişisel uygulamalarla paylaşılamıyor"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"BT yöneticiniz kişisel uygulamalar ile iş uygulamaları arasında paylaşımı engelledi"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"İş uygulamalarını açın"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"İş uygulamalarına ve kişilere erişmek için iş uygulamalarını açın"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Kullanılabilir uygulama yok"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Herhangi bir uygulama bulamadık"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"İş profilini aç"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefon aramalarında sesi kaydet veya çal"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Varsayılan çevirici uygulaması olarak atandığında bu uygulamanın telefon aramalarında sesi kaydetmesine veya çalmasına izin verir."</string> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 37bb5cd12789..e36c900fe4e8 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -197,6 +197,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Адміністратор вашої організації контролює цей пристрій і відстежує мережевий трафік. Торкніться, щоб дізнатися більше."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Доступ до геоданих змінено адміністратором"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Натисніть, щоб переглянути доступ до геоданих."</string> + <string name="country_detector" msgid="7023275114706088854">"Визначення країни"</string> + <string name="location_service" msgid="2439187616018455546">"Служби локації"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Сервіс \"Сповіщення датчика\""</string> + <string name="twilight_service" msgid="8964898045693187224">"Сервіс \"Сутінки\""</string> <string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Не можна запускати додаток для адміністраторів. Буде відновлено заводські налаштування пристрою.\n\nЯкщо у вас є запитання, зв’яжіться з адміністратором своєї організації."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Додаток <xliff:g id="OWNER_APP">%s</xliff:g> вимкнув друк."</string> @@ -251,6 +255,10 @@ <item quantity="many">Знімок екрана для звіту про помилки буде зроблено через <xliff:g id="NUMBER_1">%d</xliff:g> секунд.</item> <item quantity="other">Знімок екрана для звіту про помилки буде зроблено через <xliff:g id="NUMBER_1">%d</xliff:g> секунди.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Беззвуч. режим"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Звук ВИМК."</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Звук УВІМК."</string> @@ -552,8 +560,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Повторіть спробу."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Відбитки пальців не зареєстровано."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик тимчасово вимкнено."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Відбиток пальця <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -597,8 +604,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Не вдається перевірити обличчя. Повторіть спробу."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ви не налаштували Фейсконтроль"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"На цьому пристрої не підтримується Фейсконтроль."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик тимчасово вимкнено."</string> <string name="face_name_template" msgid="3877037340223318119">"Обличчя <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1358,6 +1364,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Налагодження USB підключено"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Торкніться, щоб вимкнути налагоджувач USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Виберіть, щоб вимкнути налагодження за USB"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Бездротове налагодження підключено"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Натисніть, щоб вимкнути бездротове налагодження"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Виберіть, щоб вимкнути бездротове налагодження."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Увімкнено режим автоматизованого тестування"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Щоб вимкнути режим автоматизованого тестування, відновіть заводські налаштування."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Послідовну консоль увімкнено"</string> @@ -1665,8 +1674,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Активний сервіс пакета <xliff:g id="PACKAGENAME">%1$s</xliff:g>, запущений у фоновому режимі, не матиме дозволу \"Коли додаток використовується\" в майбутніх складаннях R. Перегляньте go/r-bg-fgs-restriction і надішліть звіт про помилки."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Збільшити гучність понад рекомендований рівень?\n\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Використовувати швидке ввімкнення?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Якщо цей засіб увімкнено, ви можете активувати спеціальні можливості, утримуючи обидві кнопки гучності протягом трьох секунд."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Редагувати засоби"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Скасувати"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Вимкнути ярлик"</string> @@ -1909,6 +1917,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Без категорії"</string> <string name="importance_from_user" msgid="2782756722448800447">"Ви вказуєте пріоритет цих сповіщень."</string> <string name="importance_from_person" msgid="4235804979664465383">"Важливе з огляду на учасників."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g> (користувач із таким обліковим записом уже існує)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Додати мову"</string> @@ -2086,20 +2096,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Особисте"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Робоче"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Не можна надсилати дані робочим додаткам"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Не можна надсилати дані особистим додаткам"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Ваш ІТ-адміністратор заблокував обмін даними між особистими й робочими додатками"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Увімкніть робочі додатки"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Щоб отримати доступ до робочих додатків і контактів, увімкніть ці додатки"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Немає доступних додатків"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Немає додатків"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Увімкнути робочий профіль"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Записувати й відтворювати звук під час викликів"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Дозволяє цьому додатку записувати й відтворювати звук під час викликів, коли його вибрано додатком для дзвінків за умовчанням."</string> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index f2157bd805dd..10eb4ce81b24 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -191,8 +191,12 @@ <string name="device_ownership_relinquished" msgid="4080886992183195724">"منتظم نے ذاتی استعمال کے لیے آلہ کو دستبردار کیا ہے"</string> <string name="network_logging_notification_title" msgid="554983187553845004">"آلہ زیر انتظام ہے"</string> <string name="network_logging_notification_text" msgid="1327373071132562512">"آپ کی تنظیم اس آلے کا نظم کرتی ہے اور وہ نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے۔ تفاصیل کیلئے تھپتھپائیں۔"</string> - <string name="location_changed_notification_title" msgid="4119726617105166830">"آپ کے منتظم نے مقام کی ترتیبات تبدیل کر دی"</string> + <string name="location_changed_notification_title" msgid="4119726617105166830">"آپ کے منتظم نے مقام کی ترتیبات تبدیل کر دیں"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"اپنے مقام کی ترتیبات دیکھنے کے لیے تھپتھپائیں۔"</string> + <string name="country_detector" msgid="7023275114706088854">"ملک کا ڈیٹیکٹر"</string> + <string name="location_service" msgid="2439187616018455546">"مقام کی سروس"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"سینسر نوٹیفکیشن سروس"</string> + <string name="twilight_service" msgid="8964898045693187224">"شفقی سروس"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string> <string name="factory_reset_message" msgid="2657049595153992213">"منتظم کی ایپ استعمال نہیں کی جا سکتی۔ آپ کا آلہ اب مٹا دیا جائے گا۔\n\nاگر آپ کے سوالات ہیں تو اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> نے پرنٹنگ کو غیر فعال کر دیا ہے۔"</string> @@ -245,6 +249,10 @@ <item quantity="other">بگ رپورٹ کیلئے <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈز میں اسکرین شاٹ لیا جائے گا۔</item> <item quantity="one">بگ رپورٹ کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> سیکنڈ میں اسکرین شاٹ لیا جائے گا۔</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"خاموش وضع"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"آواز آف ہے"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"آواز آن ہے"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"دوبارہ کوشش کریں۔"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"کوئی فنگر پرنٹ مندرج شدہ نہیں ہے۔"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"سینسر عارضی طور غیر فعال ہے۔"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"چہرے کی توثیق نہیں کی جا سکی۔ پھر آزمائيں۔"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"آپ نے بذریعہ چہرہ غیر مقفل کرنے کو سیٹ نہیں کیا ہے۔"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"اس آلہ پر چہرے کے ذریعے غیر مقفل کرنا تعاون یافتہ نہیں ہے۔"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"سینسر عارضی طور غیر فعال ہے۔"</string> <string name="face_name_template" msgid="3877037340223318119">"چہرہ <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ڈیبگ کرنا مربوط ہو گیا"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ڈیبگنگ آف کرنے کے لیے تھپتھپائیں"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ڈیبگ کرنے کو غیر فعال کرنے کیلئے منتخب کریں۔"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"وائرلیس ڈیبگنگ منسلک ہے"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"وائرلیس ڈیبگنگ آف کرنے کے لیے تھپتھپائیں"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"وائرلیس ڈیبگنگ کرنے کو غیر فعال کرنے کے ليے منتخب کریں۔"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ٹیسٹ ہارنیس موڈ فعال ہے"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ٹیسٹ ہارنیس موڈ غیر فعال کرنے کے لیے فیکٹری ری سیٹ کریں۔"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"شمار کونسول فعال ہے"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"پس منظر <xliff:g id="PACKAGENAME">%1$s</xliff:g> سے شروع کی گئی پیش منظر کی سروس کو مستقبل کے R بلڈز میں استعمال کے دوران اجازت نہیں ہوگی۔ براہ کرم go/r-bg-fgs-restriction دیکھیں اور بگ رپورٹ دائر کریں۔"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"والیوم کو تجویز کردہ سطح سے زیادہ کریں؟\n\nزیادہ وقت تک اونچی آواز میں سننے سے آپ کی سماعت کو نقصان پہنچ سکتا ہے۔"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ایکسیسبیلٹی شارٹ کٹ استعمال کریں؟"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"شارٹ کٹس میں ترمیم کریں"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"منسوخ کریں"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"شارٹ کٹ آف کریں"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"غیر زمرہ بند"</string> <string name="importance_from_user" msgid="2782756722448800447">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string> <string name="importance_from_person" msgid="4235804979664465383">"اس میں موجود لوگوں کی وجہ سے یہ اہم ہے۔"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں (اس اکاؤنٹ کے ساتھ ایک صارف پہلے سے موجود ہے) ؟"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ نئے صارف کو تخلیق کرنے کے لیے <xliff:g id="APP">%1$s</xliff:g> کو اجازت دیں ؟"</string> <string name="language_selection_title" msgid="52674936078683285">"ایک زبان شامل کریں"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ذاتی"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"دفتر"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"ورک ایپس کے ساتھ اشتراک نہیں کر سکتے"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"ذاتی ایپس کے ساتھ اشتراک نہیں کر سکتے"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"آپ کے IT منتظم نے ذاتی اور ورک ایپس کے درمیان اشتراک کرنے کو مسدود کر دیا"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"ورک ایپس آن کریں"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"ورک ایپس اور رابطوں تک رسائی حاصل کرنے کے لیے ورک ایپس آن کریں"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"کوئی ایپ دستیاب نہیں"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"ہمیں کوئی ایپ نہیں مل سکی"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"ورک کا سوئچ آن کریں"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"ٹیلیفون کالز میں آڈیو ریکارڈ کریں یا چلائیں"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"اس ایپ کو، جب ڈیفالٹ ڈائلر ایپلیکیشن کے بطور تفویض کیا جاتا ہے، تو ٹیلیفون کالز میں آڈیو ریکارڈ کرنے یا چلانے کی اجازت دیتا ہے۔"</string> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index ee5a7d270073..526d88b87590 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Tashkilotingiz bu qurilmani boshqaradi va tarmoq trafigini nazorat qilishi mumkin. Tafsilotlar uchun bosing."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Joylashuv sozlamalari administratoringiz tomonidan oʻzgartirildi"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Joylashuv sozlamalarini koʻrish uchun bosing."</string> + <string name="country_detector" msgid="7023275114706088854">"Mamlakatni aniqlash"</string> + <string name="location_service" msgid="2439187616018455546">"Joylashuvni aniqlash xizmati"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Sensorli bildirishnoma xizmati"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight xizmati"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Administrator ilovasini ishlatib bo‘lmaydi. Qurilmada barcha ma’lumotlar o‘chirib tashlanadi.\n\nSavollaringiz bo‘lsa, administrator bilan bog‘laning."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Chop etish funksiyasi <xliff:g id="OWNER_APP">%s</xliff:g> tomonidan faolsizlantirilgan."</string> @@ -245,6 +249,10 @@ <item quantity="other">Xatoliklar hisoboti uchun skrinshot <xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng olinadi.</item> <item quantity="one">Xatoliklar hisoboti uchun skrinshot <xliff:g id="NUMBER_0">%d</xliff:g> soniyadan so‘ng olinadi.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Ovozsiz rejim"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Tovush o‘chirilgan"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"YONIQ"</string> @@ -431,7 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"Bu imtiyozli | tizim ilovasi istalgan vaqtda tizim kamerasi orqali surat va videolar olishi mumkin. Ilovada android.permission.CAMERA ruxsati ham yoqilgan boʻlishi talab qilinadi"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"tebranishni boshqarish"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"Ilova tebranishli signallarni boshqarishi mumkin."</string> - <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Ilovaga tebranish holatiga kirish ruxsatini beradi."</string> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Ilovaga tebranish holatini aniqlash ruxsatini beradi."</string> <string name="permlab_callPhone" msgid="1798582257194643320">"telefon raqamlariga tog‘ridan to‘g‘ri qo‘ng‘iroq qilish"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"Ilovaga sizning yordamingizsiz telefonga qo‘ng‘iroq qilish imkonini beradi. Bu kutilmagan qo‘ng‘iroqlarni amalga oshirishi yoki ortiqcha to‘lovlarni yuzaga keltirishi mumkin. Shunga e’tibor qilinki, u favqulodda telefon raqamlariga qo‘ng‘iroqlar qilishga ruxsat bermaydi. Zararli ilovalar sizdan so‘ramasdan qo‘ng‘iroqlarni amalga oshirib, pulingizni sarflashi mumkin."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"IMS qo‘ng‘iroq xizmatiga kirish"</string> @@ -1316,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB orqali nosozliklarni aniqlash"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB orqali nosozliklarni aniqlashni faolsizlantirish uchun bosing"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB orqali nosozliklarni tuzatishni o‘chirib qo‘yish uchun bosing."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Simsiz tarmoq nosozliklari faqat ulangan tarmoqda aniqlanadi"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Simsiz tarmoqdagi nosozliklar aniqlanishini faolsizlantirish uchun bosing"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Simsiz tarmoqdagi nosozliklar aniqlanishini faolsizlantirish uchun bosing."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Xavfsizlik sinovi rejimi yoqildi"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Xavfsizlik sinovi rejimini faolsizlantirish uchun zavod sozlamalariga qaytaring."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Davomiy port terminali yoqildi"</string> @@ -1619,7 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fonda faol <xliff:g id="PACKAGENAME">%1$s</xliff:g> xizmatini ishga tushirish uchun kelgusi R nashrlarida ishlatilayotganda ruxsat berish imkoniyati boʻlmaydi. go/r-bg-fgs-restriction sahifasiga kiring va xatolik hisobotini yuboring."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Tovush balandligi tavsiya etilgan darajadan ham yuqori qilinsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Tezkor ishga tushirishdan foydalanilsinmi?"</string> - <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala ovoz balandligini boshqarish tugmasini 3 soniya bosib turing."</string> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala tovush tugmasini 3 soniya bosib turing."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Tezkor tugmalarni tahrirlash"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Bekor qilish"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string> @@ -1842,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Turkumlanmagan"</string> <string name="importance_from_user" msgid="2782756722448800447">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string> <string name="importance_from_person" msgid="4235804979664465383">"Bu odamlar siz uchun muhim."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi (bunday hisobdagi foydalanuvchi allaqachon mavjud) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Til qoʻshish"</string> @@ -2015,12 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Shaxsiy"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Ish"</string> - <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ishchi ilovalarga ulashilmaydi"</string> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ishga oid ilovalarga ulashilmaydi"</string> <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Shaxsiy ilovalarga ulashilmaydi"</string> - <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Shaxsiy va ishchi ilovalararo axborot ulashish AT administratori tomonidan taqiqlangan"</string> - <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ishchi ilovalarni yoqish"</string> - <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ishchi ilova va kontaktlarni ochish uchun ishchi ilovalarni yoqing"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Shaxsiy va ishga oid ilovalararo axborot ulashish AT administratori tomonidan taqiqlangan"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Ishga oid ilovalarni yoqish"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Ishga oid ilova va kontaktlarni ochish uchun ishga oid ilovalarni yoqing"</string> <string name="resolver_no_apps_available" msgid="7710339903040989654">"Mos ilova topilmadi"</string> <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Hech qanday ilova topilmadi"</string> - <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ishchi rejimni yoqish"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Ish rejimini yoqish"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Telefondagi suhbatlarni yozib olish va ularni ijro qilish"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Bu ilova chaqiruvlar uchun asosiy ilova sifatida tayinlanganda u telefon chaqiruvlarida suhbatlarni yozib olish va shu audiolarni ijro etish imkonini beradi."</string> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 1a8a2752e90e..4f67627b9904 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Tổ chức của bạn sẽ quản lý thiết bị này và có thể theo dõi lưu lượng truy cập mạng. Nhấn để biết chi tiết."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Quản trị viên của bạn đã thay đổi các tùy chọn cài đặt vị trí"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Nhấn để xem các tùy chọn cài đặt vị trí của bạn."</string> + <string name="country_detector" msgid="7023275114706088854">"Trình phát hiện quốc gia"</string> + <string name="location_service" msgid="2439187616018455546">"Dịch vụ vị trí"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Dịch vụ Thông báo của cảm biến"</string> + <string name="twilight_service" msgid="8964898045693187224">"Dịch vụ Twilight"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Không thể sử dụng ứng dụng quản trị. Thiết bị của bạn sẽ bị xóa ngay bây giờ.\n\nHãy liên hệ với quản trị viên của tổ chức nếu bạn có thắc mắc."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> đã tắt tính năng in."</string> @@ -245,6 +249,10 @@ <item quantity="other">Sẽ chụp ảnh màn hình để báo cáo lỗi sau <xliff:g id="NUMBER_1">%d</xliff:g> giây.</item> <item quantity="one">Sẽ chụp ảnh màn hình để báo cáo lỗi sau <xliff:g id="NUMBER_0">%d</xliff:g> giây.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Chế độ im lặng"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Âm thanh TẮT"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Âm thanh BẬT"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Thử lại."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Chưa đăng ký vân tay."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Đã tạm thời tắt cảm biến."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Không thể xác minh khuôn mặt. Hãy thử lại."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Bạn chưa thiết lập tính năng mở khóa bằng khuôn mặt."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Thiết bị này không hỗ trợ tính năng mở khóa bằng khuôn mặt."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Đã tạm thời tắt cảm biến."</string> <string name="face_name_template" msgid="3877037340223318119">"Khuôn mặt <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Đã kết nối chế độ gỡ lỗi qua USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Nhấn để tắt chế độ gỡ lỗi qua USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Chọn để tắt chế độ gỡ lỗi qua USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Đã kết nối tính năng gỡ lỗi không dây"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Nhấn để tắt tính năng gỡ lỗi không dây"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Chọn để tắt tính năng gỡ lỗi không dây."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Đã bật Chế độ khai thác kiểm thử"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Khôi phục cài đặt gốc để tắt Chế độ khai thác kiểm thử."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Đã bật bảng điều khiển cổng nối tiếp"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Dịch vụ trên nền trước đã bắt đầu ở nền từ <xliff:g id="PACKAGENAME">%1$s</xliff:g> sẽ không có quyền khi đang sử dụng trong các bản dựng R trong tương lai. Vui lòng xem go/r-bg-fgs-restriction và gửi báo cáo lỗi."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bạn tăng âm lượng lên quá mức khuyên dùng?\n\nViệc nghe ở mức âm lượng cao trong thời gian dài có thể gây tổn thương thính giác của bạn."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sử dụng phím tắt Hỗ trợ tiếp cận?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Khi phím tắt này đang bật, thao tác nhấn cả hai nút âm lượng trong 3 giây sẽ mở tính năng hỗ trợ tiếp cận."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Chỉnh sửa phím tắt"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Hủy"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Tắt phím tắt"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Chưa được phân loại"</string> <string name="importance_from_user" msgid="2782756722448800447">"Bạn đặt tầm quan trọng của các thông báo này."</string> <string name="importance_from_person" msgid="4235804979664465383">"Thông báo này quan trọng vì những người có liên quan."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g> (đã tồn tại người dùng có tài khoản này)?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Thêm ngôn ngữ"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Cá nhân"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Cơ quan"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Không thể chia sẻ với các ứng dụng công việc"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Không thể chia sẻ với các ứng dụng cá nhân"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Quản trị viên CNTT của bạn đã chặn hoạt động chia sẻ giữa các ứng dụng cá nhân và công việc"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Bật các ứng dụng công việc"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Bật ứng dụng công việc để truy cập vào phần những người liên hệ và ứng dụng công việc"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Không có ứng dụng nào"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Chúng tôi không tìm thấy bất kỳ ứng dụng nào"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Bật hồ sơ công việc"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Ghi âm hoặc phát âm thanh trong cuộc gọi điện thoại"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Cho phép ứng dụng này ghi âm hoặc phát âm thanh trong cuộc gọi điện thoại khi được chỉ định làm ứng dụng trình quay số mặc định."</string> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 2339a44719e4..5ac1f0a0f52e 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"贵单位会管理该设备,且可能会监控网络流量。点按即可了解详情。"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"您的管理员已更改位置信息设置"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"点按即可查看您的位置信息设置。"</string> + <string name="country_detector" msgid="7023275114706088854">"国家/地区检测器"</string> + <string name="location_service" msgid="2439187616018455546">"位置信息服务"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"传感器通知服务"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight 服务"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string> <string name="factory_reset_message" msgid="2657049595153992213">"无法使用管理应用,系统现在将清空您的设备。\n\n如有疑问,请与您所在单位的管理员联系。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"“<xliff:g id="OWNER_APP">%s</xliff:g>”已停用打印功能。"</string> @@ -245,6 +249,10 @@ <item quantity="other">系统将在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后对错误报告进行截屏。</item> <item quantity="one">系统将在 <xliff:g id="NUMBER_0">%d</xliff:g> 秒后对错误报告进行截屏。</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"静音模式"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"声音已关闭"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"声音已开启"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"请重试。"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未注册任何指纹。"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"传感器已暂时停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"无法验证人脸,请重试。"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"您尚未设置人脸解锁。"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"此设备不支持人脸解锁。"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"传感器已暂时停用。"</string> <string name="face_name_template" msgid="3877037340223318119">"面孔 <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"已连接到 USB 调试"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"点按即可关闭 USB 调试"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"选择即可停用 USB 调试功能。"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"已连接到无线调试"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"点按即可关闭无线调试功能"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"选择即可停用无线调试功能。"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"自动化测试框架模式已启用"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"恢复出厂设置以停用自动化测试框架模式。"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"已启用序列控制台"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"在未来的 R 版本中,在后台启动的 <xliff:g id="PACKAGENAME">%1$s</xliff:g> 中的前台服务将不具有仅在使用时授予的权限。请访问 go/r-bg-fgs-restriction 并提交错误报告。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要将音量调高到建议的音量以上吗?\n\n长时间保持高音量可能会损伤听力。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用无障碍快捷方式吗?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"启用这项快捷方式后,同时按下两个音量按钮 3 秒钟即可启动无障碍功能。"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"修改快捷方式"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"关闭快捷方式"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"未分类"</string> <string name="importance_from_user" msgid="2782756722448800447">"这些通知的重要程度由您来设置。"</string> <string name="importance_from_person" msgid="4235804979664465383">"这条通知涉及特定的人,因此被归为重要通知。"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string> <string name="language_selection_title" msgid="52674936078683285">"添加语言"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"个人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"无法与工作应用共享数据"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"无法与个人应用共享数据"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"您的 IT 管理员已禁止在个人应用和工作应用之间共享数据"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"打开工作应用"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"打开工作应用以访问工作应用和联系人"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"没有可用的应用"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"系统找不到任何应用"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"打开工作资料"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"录制或播放电话通话音频"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"允许此应用在被指定为默认拨号器应用时录制或播放电话通话音频。"</string> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 94783a00e355..44de6bf1bf3d 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"您的機構會管理此裝置,並可能會監控網絡流量。輕按即可瞭解詳情。"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"您的管理員變更了位置設定"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"輕按即可查看位置設定。"</string> + <string name="country_detector" msgid="7023275114706088854">"國家/地區偵測器"</string> + <string name="location_service" msgid="2439187616018455546">"定位服務"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"感應器通知服務"</string> + <string name="twilight_service" msgid="8964898045693187224">"暮光服務"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理員應用程式。系統會現在清除您的裝置。\n\n如有任何疑問,請聯絡您的機構管理員。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」暫停了列印。"</string> @@ -245,6 +249,10 @@ <item quantity="other">系統將在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item> <item quantity="one">系統將在 <xliff:g id="NUMBER_0">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"靜音模式"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"關閉音效"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"音效已開啟"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"再試一次。"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未註冊任何指紋"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"無法驗證臉孔。請再試一次。"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"您尚未設定「臉孔解鎖」。"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"此裝置不支援「臉孔解鎖」。"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string> <string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"已連接 USB 偵錯工具"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"輕按即可關閉 USB 偵錯功能"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"選取即可停用 USB 偵錯。"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"已連接無線偵錯"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"輕按即可關閉無線偵錯功能"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"選取即可停用無線偵錯功能。"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"已啟用測試工具模式"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"請將裝置回復原廠設定,以停用測試工具模式。"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"已啟用序列控制器"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"從「<xliff:g id="PACKAGENAME">%1$s</xliff:g>」啟動前景服務的背景將不會在未來的 R 版本中提供「僅在使用此應用程式時允許」權限。請參閱 go/r-bg-fgs-restriction,提交錯誤報告。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量 (比建議的音量更大聲) 嗎?\n\n長時間聆聽高分貝音量可能會導致您的聽力受損。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙功能快速鍵嗎?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用快速鍵後,同時按住音量按鈕 3 秒便可啟用無障礙功能。"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"關閉快速鍵"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"未分類"</string> <string name="importance_from_user" msgid="2782756722448800447">"您可以設定這些通知的重要性。"</string> <string name="importance_from_person" msgid="4235804979664465383">"列為重要的原因:涉及的人。"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者 (此帳戶目前已有此使用者) 嗎?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string> <string name="language_selection_title" msgid="52674936078683285">"新增語言"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"公司"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"無法與工作應用程式分享"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"無法與個人應用程式分享"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"您的 IT 管理員已封鎖個人和工作應用程式之間的分享功能"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"開啟工作應用程式"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"開啟工作應用程式以存取工作應用程式和聯絡人"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"沒有可用的應用程式"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"系統找不到任何應用程式"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"開啟工作設定檔"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"在電話通話中錄音或播放音訊"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"如將此應用程式指定為預設撥號器應用程式,則允許應用程式在電話通話中錄音或播放音訊。"</string> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index f3da0d84894a..9e1b0d42a8f2 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"貴機構會管理這個裝置,且可能監控網路流量。輕觸即可瞭解詳情。"</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"你的管理員變更了位置資訊設定"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"輕觸即可查看位置資訊設定。"</string> + <string name="country_detector" msgid="7023275114706088854">"國家/地區偵測器"</string> + <string name="location_service" msgid="2439187616018455546">"定位服務"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"感應器通知服務"</string> + <string name="twilight_service" msgid="8964898045693187224">"Twilight 服務"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string> <string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理應用程式,系統現在將清除你裝置中的資料。\n\n如有任何問題,請與貴機構的管理員聯絡。"</string> <string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」已停用列印功能。"</string> @@ -245,6 +249,10 @@ <item quantity="other">系統將在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item> <item quantity="one">系統將在 <xliff:g id="NUMBER_0">%d</xliff:g> 秒後擷取錯誤報告的螢幕畫面。</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"靜音模式"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"音效已關閉"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"音效已開啟"</string> @@ -431,7 +439,7 @@ <string name="permdesc_systemCamera" msgid="544730545441964482">"取得存取權後,這個系統應用程式就隨時可以使用系統攝影機拍照及錄影。此外,你也必須將 android.permission.CAMERA 權限授予這個應用程式"</string> <string name="permlab_vibrate" msgid="8596800035791962017">"控制震動"</string> <string name="permdesc_vibrate" msgid="8733343234582083721">"允許應用程式控制震動。"</string> - <string name="permdesc_vibrator_state" msgid="7050024956594170724">"允許應用程式存取震動狀態。"</string> + <string name="permdesc_vibrator_state" msgid="7050024956594170724">"允許應用程式存取震動功能狀態。"</string> <string name="permlab_callPhone" msgid="1798582257194643320">"直接撥打電話號碼"</string> <string name="permdesc_callPhone" msgid="5439809516131609109">"允許應用程式自行撥打電話,但可能產生非預期的費用或撥打非預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能利用此功能擅自撥打電話,增加你不必要的額外支出。"</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"存取 IMS 撥號服務"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"請再試一次。"</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未登錄任何指紋。"</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"無法驗證臉孔,請再試一次。"</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"你尚未設定人臉解鎖功能。"</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"這個裝置不支援人臉解鎖功能。"</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string> <string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"已連接 USB 偵錯工具"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"輕觸即可關閉 USB 偵錯功能"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"選取這個選項以停用 USB 偵錯功能。"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"無線偵錯已連線"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"輕觸即可關閉無線偵錯功能"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"選取即可停用無線偵錯功能。"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"測試控管工具模式已啟用"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"恢復原廠設定以停用測試控管工具模式。"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"已啟用序列主控台"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"來自「<xliff:g id="PACKAGENAME">%1$s</xliff:g>」的背景啟動前景服務不會具備未來 R 版本的使用狀態權限。請前往 go/r-bg-fgs-restriction 並提交錯誤報告。"</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"要調高音量,比建議的音量更大聲嗎?\n\n長時間聆聽高分貝音量可能會使你的聽力受損。"</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"要使用無障礙捷徑嗎?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用捷徑功能,只要同時按下兩個音量按鈕 3 秒,就能啟動無障礙功能。"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"編輯捷徑"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"取消"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"停用捷徑"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"未分類"</string> <string name="importance_from_user" msgid="2782756722448800447">"這些通知的重要性由你決定。"</string> <string name="importance_from_person" msgid="4235804979664465383">"這則通知涉及特定人士,因此被歸為重要通知。"</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> (這個帳戶目前已有使用者) 建立新使用者嗎?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string> <string name="language_selection_title" msgid="52674936078683285">"新增語言"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"無法與工作應用程式分享"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"無法與個人應用程式分享"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"你的 IT 管理員已封鎖個人和工作應用程式之間的分享功能"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"開啟工作應用程式"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"開啟工作應用程式即可存取工作應用程式和聯絡人"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"沒有可用的應用程式"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"系統找不到任何應用程式"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"啟用工作資料夾"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"在通話期間錄製或播放音訊"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"將這個應用程式指派為預設撥號應用程式時,允許應用程式在通話期間錄製或播放音訊。"</string> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index d4a6c26b432d..f29ac2fd8a75 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -193,6 +193,10 @@ <string name="network_logging_notification_text" msgid="1327373071132562512">"Inhlangano yakho iphethe le divayisi futhi kungenzeka ingaqaphi ithrafikhi yenethiwekhi. Thephela imininingwane."</string> <string name="location_changed_notification_title" msgid="4119726617105166830">"Izilungiselelo zendawo zishintshwe umphathi wakho"</string> <string name="location_changed_notification_text" msgid="198907268219396399">"Thepha ukuze ubone izilungiselelo zakho zendawo."</string> + <string name="country_detector" msgid="7023275114706088854">"Isitholi Sezwe"</string> + <string name="location_service" msgid="2439187616018455546">"Isevisi Yendawo"</string> + <string name="sensor_notification_service" msgid="7474531979178682676">"Isevisi Yesaziso Senzwa"</string> + <string name="twilight_service" msgid="8964898045693187224">"Isevisi Yangovivi"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string> <string name="factory_reset_message" msgid="2657049595153992213">"Uhlelo lokusebenza lomlawuli alikwazi ukusetshenziswa. Idivayisi yakho manje izosuswa.\n\nUma unemibuzo, xhumana nomlawuli wezinhlangano zakho."</string> <string name="printing_disabled_by" msgid="3517499806528864633">"Ukuphrinta kukhutshazwe nge-<xliff:g id="OWNER_APP">%s</xliff:g>."</string> @@ -245,6 +249,10 @@ <item quantity="one">Ithathela umbiko wesiphazamisi isithombe-skrini kumasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>.</item> <item quantity="other">Ithathela umbiko wesiphazamisi isithombe-skrini kumasekhondi angu-<xliff:g id="NUMBER_1">%d</xliff:g>.</item> </plurals> + <!-- no translation found for bugreport_screenshot_success_toast (7986095104151473745) --> + <skip /> + <!-- no translation found for bugreport_screenshot_failure_toast (6736320861311294294) --> + <skip /> <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Imodi ethulile"</string> <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Umsindo UVALIWE"</string> <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Umsindo UVULIWE"</string> @@ -546,8 +554,7 @@ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Zama futhi."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Azikho izigxivizo zeminwe ezibhalisiwe."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string> - <!-- no translation found for fingerprint_error_security_update_required (7750187320640856433) --> - <skip /> + <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Inzwa ikhutshazwe okwesikhashana."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> @@ -591,8 +598,7 @@ <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ayikwazi ukuqinisekisa ubuso. Zama futhi."</string> <string name="face_error_not_enrolled" msgid="7369928733504691611">"Awukakasethi i-face unlock."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"I-face unlock ayisekelwe kule divayisi."</string> - <!-- no translation found for face_error_security_update_required (5076017208528750161) --> - <skip /> + <string name="face_error_security_update_required" msgid="5076017208528750161">"Inzwa ikhutshazwe okwesikhashana."</string> <string name="face_name_template" msgid="3877037340223318119">"Ubuso be-<xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> </string-array> @@ -1318,6 +1324,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Ukulungisa iphutha le-USB kuxhunyiwe"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Thepha ukuze uvale ukulungisa amaphutha kwe-USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Khetha ukuvimbela ukulungisa iphutha le-USB."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Ukulungisa amaphutha okungenantambo kuxhunyiwe"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Thepha ukuze ucishe ukulungisa amaphutha okungenantambo"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Khetha ukukhubaza ukulungisa amaphutha okungenantambo."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Imodi yokuhlola i-harness inikwe amandla"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Yenza ukusetha kabusha kwasekuqaleni ukuze ukhubaze imodi yokuqina yokuhlola."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"I-serial console inikwe amandla"</string> @@ -1621,8 +1630,7 @@ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ingemuva eqalise isevisi yasemuva kusuka ku-<xliff:g id="PACKAGENAME">%1$s</xliff:g> ngeke ithole imvume yokusebenzisa yesikhathi ekwakheni kwe-R ezayo. Sicela ubone i-go/r-bg-fgs-restriction bese ufayele umbiko wesiphazamiso."</string> <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Khuphukisa ivolumu ngaphezu kweleveli enconyiwe?\n\nUkulalela ngevolumu ephezulu izikhathi ezide kungahle kulimaze ukuzwa kwakho."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sebenzisa isinqamuleli sokufinyelela?"</string> - <!-- no translation found for accessibility_shortcut_toogle_warning (4161716521310929544) --> - <skip /> + <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Uma isinqamuleli sivuliwe, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqalisa isici sokufinyelela."</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Hlela izinqamuleli"</string> <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Khansela"</string> <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Vala isinqamuleli"</string> @@ -1845,6 +1853,8 @@ <string name="default_notification_channel_label" msgid="3697928973567217330">"Akufakwanga esigabeni"</string> <string name="importance_from_user" msgid="2782756722448800447">"Usethe ukubaluleka kwalezi zaziso."</string> <string name="importance_from_person" msgid="4235804979664465383">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string> + <!-- no translation found for notification_history_title_placeholder (7748630986182249599) --> + <skip /> <string name="user_creation_account_exists" msgid="2239146360099708035">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> (Umsebenzisi onale akhawunti usevele ukhona) ?"</string> <string name="user_creation_adding" msgid="7305185499667958364">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string> <string name="language_selection_title" msgid="52674936078683285">"Engeza ulwimi"</string> @@ -2018,20 +2028,14 @@ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Okomuntu siqu"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Umsebenzi"</string> - <!-- no translation found for resolver_cant_share_with_work_apps (7539495559434146897) --> - <skip /> - <!-- no translation found for resolver_cant_share_with_personal_apps (8020581735267157241) --> - <skip /> - <!-- no translation found for resolver_cant_share_cross_profile_explanation (3536237105241882679) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps (8987359079870455469) --> - <skip /> - <!-- no translation found for resolver_turn_on_work_apps_explanation (6322467455509618928) --> - <skip /> - <!-- no translation found for resolver_no_apps_available (7710339903040989654) --> - <skip /> - <!-- no translation found for resolver_no_apps_available_explanation (4662694431121196560) --> - <skip /> - <!-- no translation found for resolver_switch_on_work (8294542702883688533) --> - <skip /> + <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ayikwazi ukwabelana ngezinhlelo zokusebenza zomsebenzi"</string> + <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Ayikwazi ukwabelana ngezinhlelo zokusebenza zomuntu siqu"</string> + <string name="resolver_cant_share_cross_profile_explanation" msgid="3536237105241882679">"Umphathi wakho we-IT uvimbe ukwabelana phakathi kwezinhlelo zokusebenza zomuntu siqu nezomsebenzi"</string> + <string name="resolver_turn_on_work_apps" msgid="8987359079870455469">"Vula izinhlelo zokusebenza zomsebenzi"</string> + <string name="resolver_turn_on_work_apps_explanation" msgid="6322467455509618928">"Vula izinhlelo zokusebenza zomsebenzi ukuze ufinyelele kuzinhlelo zokusebenza zomsebenzi noxhumana nabo"</string> + <string name="resolver_no_apps_available" msgid="7710339903040989654">"Azikho izinhlelo zokusebenza ezitholakalayo"</string> + <string name="resolver_no_apps_available_explanation" msgid="4662694431121196560">"Asikwazanga ukuthola izinhlelo zokusebenza"</string> + <string name="resolver_switch_on_work" msgid="8294542702883688533">"Shintshela emsebenzini"</string> + <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Rekhoda noma dlala umsindo kumakholi ocingo"</string> + <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Ivumela lolu hlelo lokusebenza, uma lunikezwe njengohlelo lokusebenza oluzenzakalelayo lokudayela, ukuze kurekhodwe noma kudlalwe umsindo kumakholi ocingo."</string> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 490892ed9310..eae28a073332 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2752,7 +2752,9 @@ <!-- The amount to scale reduced scale snapshots for Overview and snapshot starting windows. Reduced scale snapshots are loaded before full screen snapshots to improve load times and - minimize the chance the user will see an empty task card. --> + minimize the chance the user will see an empty task card. If set to 0, reduced scale + snapshots are disabled, and snapshots will only be stored at config_highResTaskSnapshotScale + --> <item name="config_lowResTaskSnapshotScale" format="float" type="dimen">0.5</item> <!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. --> @@ -3957,14 +3959,14 @@ <!-- Component name for the default module metadata provider on this device --> <string name="config_defaultModuleMetadataProvider" translatable="false">com.android.modulemetadata</string> - <!-- This is the default launcher component to use on secondary displays that support system - decorations. - This launcher activity must support multiple instances and have corresponding launch mode - set in AndroidManifest. + <!-- This is the default launcher package with an activity to use on secondary displays that + support system decorations. + This launcher package must have an activity that supports multiple instances and has + corresponding launch mode set in AndroidManifest. {@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} --> - <string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string> + <string name="config_secondaryHomePackage" translatable="false">com.android.launcher3</string> - <!-- Force secondary home launcher specified in config_secondaryHomeComponent always. If this is + <!-- Force secondary home launcher specified in config_secondaryHomePackage always. If this is not set, secondary home launcher can be replaced by user. --> <bool name ="config_useSystemProvidedLauncherForSecondary">false</bool> @@ -4408,4 +4410,13 @@ <!-- Whether to default to an expanded list of users on the lock screen user switcher. --> <bool name="config_expandLockScreenUserSwitcher">false</bool> + + <!-- Toasts posted from these packages will be shown to the current user, regardless of the user + the process belongs to. This is useful for packages that run under a single user but serve + multiple users, e.g. the system. + These packages MUST be able to add flag SYSTEM_FLAG_SHOW_FOR_ALL_USERS to a window. --> + <string-array name="config_toastCrossUserPackages" translatable="false"> + <item>android</item> + <item>com.android.systemui</item> + </string-array> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index e1d94f50f260..c9e6dd86245e 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -764,7 +764,6 @@ <dimen name="chooser_preview_image_border">1dp</dimen> <dimen name="chooser_preview_image_max_dimen">200dp</dimen> <dimen name="chooser_preview_width">-1px</dimen> - <dimen name="chooser_target_width">90dp</dimen> <dimen name="chooser_header_scroll_elevation">4dp</dimen> <dimen name="chooser_max_collapsed_height">288dp</dimen> <dimen name="chooser_direct_share_label_placeholder_max_width">72dp</dimen> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index df1f46f10967..5f390b26ea5d 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -584,6 +584,12 @@ <!-- Format for build summary info [CHAR LIMIT=NONE] --> <string name="bugreport_status" translatable="false">%s (%s)</string> + <!-- Toast for taking screenshot with bugreport successfully. [CHAR_LIMIT=100] --> + <string name="bugreport_screenshot_success_toast">Screenshot taken with bug report</string> + + <!-- Toast for failed to take screenshot with bugreport. [CHAR_LIMIT=100] --> + <string name="bugreport_screenshot_failure_toast">Failed to take screenshot with bug report</string> + <!-- label for item that enables silent mode in phone options dialog --> <string name="global_action_toggle_silent_mode">Silent mode</string> @@ -4918,6 +4924,8 @@ <string name="importance_from_user">You set the importance of these notifications.</string> <string name="importance_from_person">This is important because of the people involved.</string> + <string name="notification_history_title_placeholder">Custom app notification</string> + <!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] --> <string name="user_creation_account_exists">Allow <xliff:g id="app" example="Gmail">%1$s</xliff:g> to create a new User with <xliff:g id="account" example="foobar@gmail.com">%2$s</xliff:g> (a User with this account already exists) ?</string> <!-- Message to user that app is trying to create user for a specified account. [CHAR LIMIT=none] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 7690b94906dd..61e4000ab49e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1789,6 +1789,8 @@ <java-symbol type="string" name="bugreport_option_full_title" /> <java-symbol type="string" name="bugreport_option_interactive_summary" /> <java-symbol type="string" name="bugreport_option_interactive_title" /> + <java-symbol type="string" name="bugreport_screenshot_failure_toast" /> + <java-symbol type="string" name="bugreport_screenshot_success_toast" /> <java-symbol type="string" name="bugreport_status" /> <java-symbol type="string" name="bugreport_title" /> <java-symbol type="string" name="faceunlock_multiple_failures" /> @@ -2734,7 +2736,6 @@ <java-symbol type="string" name="chooser_no_direct_share_targets" /> <java-symbol type="drawable" name="chooser_row_layer_list" /> <java-symbol type="dimen" name="chooser_view_spacing" /> - <java-symbol type="dimen" name="chooser_target_width" /> <java-symbol type="dimen" name="chooser_edge_margin_thin" /> <java-symbol type="dimen" name="chooser_edge_margin_normal" /> <java-symbol type="dimen" name="chooser_preview_image_font_size"/> @@ -3678,7 +3679,7 @@ <java-symbol type="string" name="config_defaultModuleMetadataProvider" /> <!-- For Secondary Launcher --> - <java-symbol type="string" name="config_secondaryHomeComponent" /> + <java-symbol type="string" name="config_secondaryHomePackage" /> <java-symbol type="bool" name="config_useSystemProvidedLauncherForSecondary" /> <java-symbol type="string" name="battery_saver_notification_channel_name" /> @@ -3904,4 +3905,9 @@ <java-symbol type="bool" name="config_expandLockScreenUserSwitcher" /> <java-symbol type="string" name="loading" /> + + <java-symbol type="array" name="config_toastCrossUserPackages" /> + + <java-symbol type="string" name="notification_history_title_placeholder" /> + </resources> diff --git a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java index 4c2ca7eefcc1..13000e943141 100644 --- a/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java +++ b/core/tests/coretests/src/android/service/controls/ControlProviderServiceTest.java @@ -284,12 +284,16 @@ public class ControlProviderServiceTest { } @Override - public void loadAvailableControls(Consumer<List<Control>> cb) { - cb.accept(mControls); + public Publisher<Control> createPublisherForAllAvailable() { + return new Publisher<Control>() { + public void subscribe(final Subscriber s) { + s.onSubscribe(createSubscription(s, mControls)); + } + }; } @Override - public Publisher<Control> publisherFor(List<String> ids) { + public Publisher<Control> createPublisherFor(List<String> ids) { return new Publisher<Control>() { public void subscribe(final Subscriber s) { s.onSubscribe(createSubscription(s, mControls)); @@ -298,7 +302,7 @@ public class ControlProviderServiceTest { } @Override - public Publisher<Control> publisherForSuggested() { + public Publisher<Control> createPublisherForSuggested() { return new Publisher<Control>() { public void subscribe(final Subscriber s) { s.onSubscribe(createSubscription(s, mControls)); diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index aa5101ee4141..50cd5a3b01b5 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -123,7 +123,7 @@ public class InsetsAnimationControlImplTest { mController = new InsetsAnimationControlImpl(controls, new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(), mMockController, 10 /* durationMs */, new LinearInterpolator(), - false /* fade */, LAYOUT_INSETS_DURING_ANIMATION_SHOWN); + false /* fade */, LAYOUT_INSETS_DURING_ANIMATION_SHOWN, 0 /* animationType */); } @Test diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java index 14999c7f5642..623008eafe10 100644 --- a/core/tests/coretests/src/android/view/KeyEventTest.java +++ b/core/tests/coretests/src/android/view/KeyEventTest.java @@ -19,6 +19,7 @@ package android.view; import static android.view.Display.INVALID_DISPLAY; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import android.os.Parcel; @@ -28,10 +29,14 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.HashSet; +import java.util.Set; + @SmallTest @RunWith(AndroidJUnit4.class) public class KeyEventTest { + private static final int ID = 0xabcdef; private static final int DOWN_TIME = 50; private static final long EVENT_TIME = 100; private static final int ACTION = KeyEvent.ACTION_DOWN; @@ -45,6 +50,8 @@ public class KeyEventTest { private static final byte[] HMAC = null; private static final String CHARACTERS = null; + private static final int ID_SOURCE_MASK = 0x3 << 30; + @Test public void testObtain() { KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, @@ -75,8 +82,7 @@ public class KeyEventTest { public void testObtainWithDisplayId() { final int displayId = 5; KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, - METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, null /* hmac*/, - CHARACTERS); + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, CHARACTERS); assertEquals(DOWN_TIME, keyEvent.getDownTime()); assertEquals(EVENT_TIME, keyEvent.getEventTime()); assertEquals(ACTION, keyEvent.getAction()); @@ -91,6 +97,52 @@ public class KeyEventTest { assertEquals(CHARACTERS, keyEvent.getCharacters()); } + /** + * Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test + * but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough. + * Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for + * this test. + */ + @Test + public void testObtainGeneratesUniqueId() { + Set<Integer> set = new HashSet<>(); + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS); + assertFalse("Found duplicate ID in round " + i, + set.contains(keyEvent.getId())); + set.add(keyEvent.getSequenceNumber()); + } + } + + @Test + public void testConstructorGeneratesUniqueId() { + Set<Integer> set = new HashSet<>(); + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT); + assertFalse("Found duplicate sequence number in round " + i, + set.contains(keyEvent.getId())); + set.add(keyEvent.getSequenceNumber()); + } + } + + @Test + public void testObtainGeneratesIdWithRightSource() { + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS); + assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId()); + } + } + + @Test + public void testConstructorGeneratesIdWithRightSource() { + for (int i = 0; i < 500; ++i) { + KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT); + assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId()); + } + } + @Test public void testParcelUnparcel() { KeyEvent key1 = createKey(); @@ -112,11 +164,12 @@ public class KeyEventTest { } private static KeyEvent createKey() { - return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, - METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS); + return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE, + DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS); } private static void compareKeys(KeyEvent key1, KeyEvent key2) { + assertEquals(key1.getId(), key2.getId()); assertEquals(key1.getDownTime(), key2.getDownTime()); assertEquals(key1.getEventTime(), key2.getEventTime()); assertEquals(key1.getAction(), key2.getAction()); diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java index 9d09830c585b..786ae89ac2ae 100644 --- a/core/tests/coretests/src/android/view/MotionEventTest.java +++ b/core/tests/coretests/src/android/view/MotionEventTest.java @@ -23,6 +23,7 @@ import static android.view.MotionEvent.TOOL_TYPE_FINGER; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import android.view.MotionEvent.PointerCoords; @@ -34,9 +35,13 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.HashSet; +import java.util.Set; + @RunWith(AndroidJUnit4.class) @SmallTest public class MotionEventTest { + private static final int ID_SOURCE_MASK = 0x3 << 30; @Test public void testObtainWithDisplayId() { @@ -138,4 +143,30 @@ public class MotionEventTest { assertEquals(30, event.getXCursorPosition(), 0.1); assertEquals(50, event.getYCursorPosition(), 0.1); } + + /** + * Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test + * but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough. + * Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for + * this test. + */ + @Test + public void testObtainGeneratesUniqueId() { + Set<Integer> set = new HashSet<>(); + for (int i = 0; i < 500; ++i) { + final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */, + ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */); + assertFalse("Found duplicate ID in round " + i, set.contains(event.getId())); + set.add(event.getSequenceNumber()); + } + } + + @Test + public void testObtainGeneratesIdWithRightSource() { + for (int i = 0; i < 500; ++i) { + final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */, + ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */); + assertEquals(0x3 << 30, ID_SOURCE_MASK & event.getId()); + } + } } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index e2adbcc600d7..0d497e113537 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -16,9 +16,13 @@ package android.view; +import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; -import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; +import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; +import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; +import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; +import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; @@ -102,79 +106,129 @@ public class ViewRootImplTest { } @Test - public void adjustLayoutParamsForInsets_layoutFullscreen() { + public void adjustLayoutParamsForCompatibility_layoutFullscreen() { assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + // Type.statusBars() must be removed. assertEquals(0, attrs.getFitInsetsTypes() & Type.statusBars()); } @Test - public void adjustLayoutParamsForInsets_layoutInScreen() { + public void adjustLayoutParamsForCompatibility_layoutInScreen() { assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); attrs.flags = FLAG_LAYOUT_IN_SCREEN; ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + // Type.statusBars() must be removed. assertEquals(0, attrs.getFitInsetsTypes() & Type.statusBars()); } @Test - public void adjustLayoutParamsForInsets_layoutHideNavigation() { + public void adjustLayoutParamsForCompatibility_layoutHideNavigation() { assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + // Type.systemBars() must be removed. assertEquals(0, attrs.getFitInsetsTypes() & Type.systemBars()); } @Test - public void adjustLayoutParamsForInsets_toast() { + public void adjustLayoutParamsForCompatibility_toast() { assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_TOAST); ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); - assertEquals(Type.systemBars(), attrs.getFitInsetsTypes() & Type.systemBars()); assertEquals(true, attrs.isFitInsetsIgnoringVisibility()); } @Test - public void adjustLayoutParamsForInsets_systemAlert() { + public void adjustLayoutParamsForCompatibility_systemAlert() { assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_SYSTEM_ALERT); ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); - assertEquals(Type.systemBars(), attrs.getFitInsetsTypes() & Type.systemBars()); assertEquals(true, attrs.isFitInsetsIgnoringVisibility()); } @Test - public void adjustLayoutParamsForInsets_noAdjust() { + public void adjustLayoutParamsForCompatibility_fitSystemBars() { + assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); + + final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); + ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + + // A window which fits system bars must fit IME, unless its type is toast or system alert. + assertEquals(Type.systemBars() | Type.ime(), attrs.getFitInsetsTypes()); + } + + @Test + public void adjustLayoutParamsForCompatibility_noAdjustLayout() { assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); final int types = Type.all(); final int sides = Side.TOP | Side.LEFT; final boolean fitMaxInsets = true; - attrs.flags = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; attrs.setFitInsetsTypes(types); attrs.setFitInsetsSides(sides); attrs.setFitInsetsIgnoringVisibility(fitMaxInsets); ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + // Fit-insets related fields must not be adjusted due to legacy system UI visibility + // after calling fit-insets related methods. assertEquals(types, attrs.getFitInsetsTypes()); assertEquals(sides, attrs.getFitInsetsSides()); assertEquals(fitMaxInsets, attrs.isFitInsetsIgnoringVisibility()); } + @Test + public void adjustLayoutParamsForCompatibility_noAdjustAppearance() { + assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); + + final ViewRootImpl viewRoot = mViewRootImpl.get(); + final WindowInsetsController controller = viewRoot.getInsetsController(); + final WindowManager.LayoutParams attrs = viewRoot.mWindowAttributes; + final int appearance = 0; + controller.setSystemBarsAppearance(appearance, 0xffffffff); + attrs.systemUiVisibility = SYSTEM_UI_FLAG_LOW_PROFILE + | SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + | SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; + ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + + // Appearance must not be adjusted due to legacy system UI visibility after calling + // setSystemBarsAppearance. + assertEquals(appearance, controller.getSystemBarsAppearance()); + } + + @Test + public void adjustLayoutParamsForCompatibility_noAdjustBehavior() { + assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); + + final ViewRootImpl viewRoot = mViewRootImpl.get(); + final WindowInsetsController controller = viewRoot.getInsetsController(); + final WindowManager.LayoutParams attrs = viewRoot.mWindowAttributes; + final int behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH; + controller.setSystemBarsBehavior(behavior); + attrs.systemUiVisibility = SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + + // Behavior must not be adjusted due to legacy system UI visibility after calling + // setSystemBarsBehavior. + assertEquals(behavior, controller.getSystemBarsBehavior()); + } + private static class ViewRootImplAccessor { private final ViewRootImpl mViewRootImpl; diff --git a/data/etc/com.android.documentsui.xml b/data/etc/com.android.documentsui.xml index 4d9860387b8d..b6671db7fa11 100644 --- a/data/etc/com.android.documentsui.xml +++ b/data/etc/com.android.documentsui.xml @@ -18,5 +18,8 @@ <privapp-permissions package="com.android.documentsui"> <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/> <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <!-- Permissions required for reading and logging compat changes --> + <permission name="android.permission.LOG_COMPAT_CHANGE"/> + <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG"/> </privapp-permissions> </permissions> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 78c7b76d38da..73d9cc06a748 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -386,6 +386,8 @@ applications that come with the platform <permission name="android.permission.ACCESS_VIBRATOR_STATE"/> <!-- Permission required for UsageStatsTest CTS test. --> <permission name="android.permission.MANAGE_NOTIFICATIONS"/> + <!-- Permission required for CompanionDeviceManager CTS test. --> + <permission name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 145fd8b824cf..99605ad64cb8 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -697,6 +697,12 @@ "group": "WM_DEBUG_FOCUS_LIGHT", "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, + "-668956537": { + "message": " THUMBNAIL %s: CREATE", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/SurfaceFreezer.java" + }, "-666510420": { "message": "With display frozen, orientationChangeComplete=%b", "level": "VERBOSE", diff --git a/data/keyboards/Vendor_0079_Product_18d4.kl b/data/keyboards/Vendor_0079_Product_18d4.kl new file mode 100644 index 000000000000..b9a2b67afb41 --- /dev/null +++ b/data/keyboards/Vendor_0079_Product_18d4.kl @@ -0,0 +1,58 @@ +# 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. + +# +# GPD Win 2 X-Box Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_044f_Product_b326.kl b/data/keyboards/Vendor_044f_Product_b326.kl new file mode 100644 index 000000000000..d248d713568f --- /dev/null +++ b/data/keyboards/Vendor_044f_Product_b326.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Thrustmaster Gamepad GP XID +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_045e_Product_028f.kl b/data/keyboards/Vendor_045e_Product_028f.kl new file mode 100644 index 000000000000..cc5b33b9a113 --- /dev/null +++ b/data/keyboards/Vendor_045e_Product_028f.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Microsoft X-Box 360 pad v2 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_046d_Product_c21e.kl b/data/keyboards/Vendor_046d_Product_c21e.kl new file mode 100644 index 000000000000..998074331d4f --- /dev/null +++ b/data/keyboards/Vendor_046d_Product_c21e.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Logitech Gamepad F510 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_046d_Product_c242.kl b/data/keyboards/Vendor_046d_Product_c242.kl new file mode 100644 index 000000000000..51eb44a62187 --- /dev/null +++ b/data/keyboards/Vendor_046d_Product_c242.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Logitech Chillstream Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_056e_Product_2004.kl b/data/keyboards/Vendor_056e_Product_2004.kl new file mode 100644 index 000000000000..9eaa36d740f9 --- /dev/null +++ b/data/keyboards/Vendor_056e_Product_2004.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Elecom JC-U3613M +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_06a3_Product_f51a.kl b/data/keyboards/Vendor_06a3_Product_f51a.kl new file mode 100644 index 000000000000..e52f25724fac --- /dev/null +++ b/data/keyboards/Vendor_06a3_Product_f51a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Saitek P3600 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_4716.kl b/data/keyboards/Vendor_0738_Product_4716.kl new file mode 100644 index 000000000000..5f3d4aa4b276 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_4716.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz Wired Xbox 360 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_4718.kl b/data/keyboards/Vendor_0738_Product_4718.kl new file mode 100644 index 000000000000..756e1e75fb34 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_4718.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz Street Fighter IV FightStick SE +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_4726.kl b/data/keyboards/Vendor_0738_Product_4726.kl new file mode 100644 index 000000000000..9d8deb36e46d --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_4726.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz Xbox 360 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_4736.kl b/data/keyboards/Vendor_0738_Product_4736.kl new file mode 100644 index 000000000000..c556e25fdeb5 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_4736.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz MicroCon Gamepad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_4740.kl b/data/keyboards/Vendor_0738_Product_4740.kl new file mode 100644 index 000000000000..cdb72683b5dd --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_4740.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz Beat Pad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_9871.kl b/data/keyboards/Vendor_0738_Product_9871.kl new file mode 100644 index 000000000000..f404065236d2 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_9871.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz Portable Drum +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_b726.kl b/data/keyboards/Vendor_0738_Product_b726.kl new file mode 100644 index 000000000000..05b737f8f919 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_b726.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz Xbox controller - MW2 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_beef.kl b/data/keyboards/Vendor_0738_Product_beef.kl new file mode 100644 index 000000000000..f969e73ec5f6 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_beef.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz JOYTECH NEO SE Advanced GamePad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_cb02.kl b/data/keyboards/Vendor_0738_Product_cb02.kl new file mode 100644 index 000000000000..bc2fc35ae172 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_cb02.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Saitek Cyborg Rumble Pad - PC/Xbox 360 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_cb03.kl b/data/keyboards/Vendor_0738_Product_cb03.kl new file mode 100644 index 000000000000..dcbf6b7487b2 --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_cb03.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Saitek P3200 Rumble Pad - PC/Xbox 360 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_cb29.kl b/data/keyboards/Vendor_0738_Product_cb29.kl new file mode 100644 index 000000000000..fe81d1c2170b --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_cb29.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Saitek Aviator Stick AV8R02 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0738_Product_f738.kl b/data/keyboards/Vendor_0738_Product_f738.kl new file mode 100644 index 000000000000..2c993807567b --- /dev/null +++ b/data/keyboards/Vendor_0738_Product_f738.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Super SFIV FightStick TE S +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_07ff_Product_ffff.kl b/data/keyboards/Vendor_07ff_Product_ffff.kl new file mode 100644 index 000000000000..637c01bdddfd --- /dev/null +++ b/data/keyboards/Vendor_07ff_Product_ffff.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz GamePad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0113.kl b/data/keyboards/Vendor_0e6f_Product_0113.kl new file mode 100644 index 000000000000..90e1f75d19c0 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0113.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Afterglow AX.1 Gamepad for Xbox 360 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_011f.kl b/data/keyboards/Vendor_0e6f_Product_011f.kl new file mode 100644 index 000000000000..8c63c6bdf0c1 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_011f.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Rock Candy Gamepad Wired Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0131.kl b/data/keyboards/Vendor_0e6f_Product_0131.kl new file mode 100644 index 000000000000..368c37606da3 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0131.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP EA Sports Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0133.kl b/data/keyboards/Vendor_0e6f_Product_0133.kl new file mode 100644 index 000000000000..815902edb863 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0133.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Xbox 360 Wired Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0139.kl b/data/keyboards/Vendor_0e6f_Product_0139.kl new file mode 100644 index 000000000000..8e2ae13f906e --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0139.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Afterglow Prismatic Wired Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_013a.kl b/data/keyboards/Vendor_0e6f_Product_013a.kl new file mode 100644 index 000000000000..3f81983bdc34 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_013a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Xbox One Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0146.kl b/data/keyboards/Vendor_0e6f_Product_0146.kl new file mode 100644 index 000000000000..6ddd056c1597 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0146.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Rock Candy Wired Controller for Xbox One +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0147.kl b/data/keyboards/Vendor_0e6f_Product_0147.kl new file mode 100644 index 000000000000..6745b7c5c294 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0147.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Marvel Xbox One Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0161.kl b/data/keyboards/Vendor_0e6f_Product_0161.kl new file mode 100644 index 000000000000..3f81983bdc34 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0161.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Xbox One Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0162.kl b/data/keyboards/Vendor_0e6f_Product_0162.kl new file mode 100644 index 000000000000..3f81983bdc34 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0162.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Xbox One Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0163.kl b/data/keyboards/Vendor_0e6f_Product_0163.kl new file mode 100644 index 000000000000..3f81983bdc34 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0163.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Xbox One Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0164.kl b/data/keyboards/Vendor_0e6f_Product_0164.kl new file mode 100644 index 000000000000..0fdfd32922cb --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0164.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Battlefield One +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0165.kl b/data/keyboards/Vendor_0e6f_Product_0165.kl new file mode 100644 index 000000000000..f9731e025f4e --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0165.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Titanfall 2 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0201.kl b/data/keyboards/Vendor_0e6f_Product_0201.kl new file mode 100644 index 000000000000..5b4c167d9999 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0201.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Pelican PL-3601 'TSZ' Wired Xbox 360 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0213.kl b/data/keyboards/Vendor_0e6f_Product_0213.kl new file mode 100644 index 000000000000..9317346faa3e --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0213.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Afterglow Gamepad for Xbox 360 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_021f.kl b/data/keyboards/Vendor_0e6f_Product_021f.kl new file mode 100644 index 000000000000..f8d3f0c08009 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_021f.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Rock Candy Gamepad for Xbox 360 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0246.kl b/data/keyboards/Vendor_0e6f_Product_0246.kl new file mode 100644 index 000000000000..daf8e4525a1e --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0246.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Rock Candy Gamepad for Xbox One 2015 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_02a6.kl b/data/keyboards/Vendor_0e6f_Product_02a6.kl new file mode 100644 index 000000000000..99a59317e724 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_02a6.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Wired Controller for Xbox One - Camo Series +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_02ab.kl b/data/keyboards/Vendor_0e6f_Product_02ab.kl new file mode 100644 index 000000000000..071a56c8c054 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_02ab.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Controller for Xbox One +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0301.kl b/data/keyboards/Vendor_0e6f_Product_0301.kl new file mode 100644 index 000000000000..a3b982d514de --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0301.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Logic3 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0346.kl b/data/keyboards/Vendor_0e6f_Product_0346.kl new file mode 100644 index 000000000000..6fefbf7ca2a4 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0346.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Rock Candy Gamepad for Xbox One 2016 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0401.kl b/data/keyboards/Vendor_0e6f_Product_0401.kl new file mode 100644 index 000000000000..a3b982d514de --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0401.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Logic3 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0413.kl b/data/keyboards/Vendor_0e6f_Product_0413.kl new file mode 100644 index 000000000000..90e1f75d19c0 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0413.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Afterglow AX.1 Gamepad for Xbox 360 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_0501.kl b/data/keyboards/Vendor_0e6f_Product_0501.kl new file mode 100644 index 000000000000..35831d148640 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_0501.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Xbox 360 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0e6f_Product_f900.kl b/data/keyboards/Vendor_0e6f_Product_f900.kl new file mode 100644 index 000000000000..44848ba0cf0d --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_f900.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Afterglow AX.1 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0f0d_Product_000a.kl b/data/keyboards/Vendor_0f0d_Product_000a.kl new file mode 100644 index 000000000000..b3aea049f63d --- /dev/null +++ b/data/keyboards/Vendor_0f0d_Product_000a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Hori Co. DOA4 FightStick +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0f0d_Product_000c.kl b/data/keyboards/Vendor_0f0d_Product_000c.kl new file mode 100644 index 000000000000..49c3addd785e --- /dev/null +++ b/data/keyboards/Vendor_0f0d_Product_000c.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Hori PadEX Turbo +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_0f0d_Product_0067.kl b/data/keyboards/Vendor_0f0d_Product_0067.kl new file mode 100644 index 000000000000..0dfccebd73c1 --- /dev/null +++ b/data/keyboards/Vendor_0f0d_Product_0067.kl @@ -0,0 +1,58 @@ +# 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. + +# +# HORIPAD ONE +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1038_Product_1430.kl b/data/keyboards/Vendor_1038_Product_1430.kl new file mode 100644 index 000000000000..e635c1d8fac6 --- /dev/null +++ b/data/keyboards/Vendor_1038_Product_1430.kl @@ -0,0 +1,58 @@ +# 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. + +# +# SteelSeries Stratus Duo +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1038_Product_1431.kl b/data/keyboards/Vendor_1038_Product_1431.kl new file mode 100644 index 000000000000..e635c1d8fac6 --- /dev/null +++ b/data/keyboards/Vendor_1038_Product_1431.kl @@ -0,0 +1,58 @@ +# 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. + +# +# SteelSeries Stratus Duo +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_11c9_Product_55f0.kl b/data/keyboards/Vendor_11c9_Product_55f0.kl new file mode 100644 index 000000000000..dbb4a7e6ecdb --- /dev/null +++ b/data/keyboards/Vendor_11c9_Product_55f0.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Nacon GC-100XF +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_12ab_Product_0301.kl b/data/keyboards/Vendor_12ab_Product_0301.kl new file mode 100644 index 000000000000..36956c1386f7 --- /dev/null +++ b/data/keyboards/Vendor_12ab_Product_0301.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP AFTERGLOW AX.1 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1430_Product_4748.kl b/data/keyboards/Vendor_1430_Product_4748.kl new file mode 100644 index 000000000000..dbe83087ab68 --- /dev/null +++ b/data/keyboards/Vendor_1430_Product_4748.kl @@ -0,0 +1,58 @@ +# 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. + +# +# RedOctane Guitar Hero X-plorer +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1430_Product_f801.kl b/data/keyboards/Vendor_1430_Product_f801.kl new file mode 100644 index 000000000000..a8f91462030c --- /dev/null +++ b/data/keyboards/Vendor_1430_Product_f801.kl @@ -0,0 +1,58 @@ +# 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. + +# +# RedOctane Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_146b_Product_0601.kl b/data/keyboards/Vendor_146b_Product_0601.kl new file mode 100644 index 000000000000..ea2f2211a18e --- /dev/null +++ b/data/keyboards/Vendor_146b_Product_0601.kl @@ -0,0 +1,58 @@ +# 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. + +# +# BigBen Interactive XBOX 360 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1532_Product_0037.kl b/data/keyboards/Vendor_1532_Product_0037.kl new file mode 100644 index 000000000000..39d8b2e6c1e2 --- /dev/null +++ b/data/keyboards/Vendor_1532_Product_0037.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Razer Sabertooth +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1532_Product_0a03.kl b/data/keyboards/Vendor_1532_Product_0a03.kl new file mode 100644 index 000000000000..75775e993979 --- /dev/null +++ b/data/keyboards/Vendor_1532_Product_0a03.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Razer Wildcat +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_15e4_Product_3f00.kl b/data/keyboards/Vendor_15e4_Product_3f00.kl new file mode 100644 index 000000000000..0d641cf9f990 --- /dev/null +++ b/data/keyboards/Vendor_15e4_Product_3f00.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Power A Mini Pro Elite +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_15e4_Product_3f0a.kl b/data/keyboards/Vendor_15e4_Product_3f0a.kl new file mode 100644 index 000000000000..9e98aeec7b73 --- /dev/null +++ b/data/keyboards/Vendor_15e4_Product_3f0a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Xbox Airflo wired controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_15e4_Product_3f10.kl b/data/keyboards/Vendor_15e4_Product_3f10.kl new file mode 100644 index 000000000000..7fb0fea910da --- /dev/null +++ b/data/keyboards/Vendor_15e4_Product_3f10.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Batarang Xbox 360 controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_162e_Product_beef.kl b/data/keyboards/Vendor_162e_Product_beef.kl new file mode 100644 index 000000000000..e7fab5dba349 --- /dev/null +++ b/data/keyboards/Vendor_162e_Product_beef.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Joytech Neo-Se Take2 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_0002.kl b/data/keyboards/Vendor_1bad_Product_0002.kl new file mode 100644 index 000000000000..d8eaaba4a90c --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_0002.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Harmonix Rock Band Guitar +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f021.kl b/data/keyboards/Vendor_1bad_Product_f021.kl new file mode 100644 index 000000000000..9fd688b0c663 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f021.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Cats Ghost Recon FS GamePad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f025.kl b/data/keyboards/Vendor_1bad_Product_f025.kl new file mode 100644 index 000000000000..03aab446cf81 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f025.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Mad Catz Call Of Duty +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f028.kl b/data/keyboards/Vendor_1bad_Product_f028.kl new file mode 100644 index 000000000000..51733313d999 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f028.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Street Fighter IV FightPad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f038.kl b/data/keyboards/Vendor_1bad_Product_f038.kl new file mode 100644 index 000000000000..79e147d06d69 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f038.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Street Fighter IV FightStick TE +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f501.kl b/data/keyboards/Vendor_1bad_Product_f501.kl new file mode 100644 index 000000000000..1282532ab5ab --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f501.kl @@ -0,0 +1,58 @@ +# 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. + +# +# HoriPad EX2 Turbo +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f506.kl b/data/keyboards/Vendor_1bad_Product_f506.kl new file mode 100644 index 000000000000..3a9d4620ba21 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f506.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Hori Real Arcade Pro.EX Premium VLX +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f900.kl b/data/keyboards/Vendor_1bad_Product_f900.kl new file mode 100644 index 000000000000..9cfceb433ad8 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f900.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Harmonix Xbox 360 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f901.kl b/data/keyboards/Vendor_1bad_Product_f901.kl new file mode 100644 index 000000000000..86d45e58ad01 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f901.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Gamestop Xbox 360 Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f903.kl b/data/keyboards/Vendor_1bad_Product_f903.kl new file mode 100644 index 000000000000..f61c05005933 --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f903.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Tron Xbox 360 controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_f904.kl b/data/keyboards/Vendor_1bad_Product_f904.kl new file mode 100644 index 000000000000..3e02a24f9e5e --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_f904.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PDP Versus Fighting Pad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_fa01.kl b/data/keyboards/Vendor_1bad_Product_fa01.kl new file mode 100644 index 000000000000..517413d2edda --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_fa01.kl @@ -0,0 +1,58 @@ +# 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. + +# +# MadCatz GamePad +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_fd00.kl b/data/keyboards/Vendor_1bad_Product_fd00.kl new file mode 100644 index 000000000000..fc6a4f85339a --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_fd00.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Razer Onza TE +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_1bad_Product_fd01.kl b/data/keyboards/Vendor_1bad_Product_fd01.kl new file mode 100644 index 000000000000..8882abf0f7be --- /dev/null +++ b/data/keyboards/Vendor_1bad_Product_fd01.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Razer Onza +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5300.kl b/data/keyboards/Vendor_24c6_Product_5300.kl new file mode 100644 index 000000000000..303e906ad721 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5300.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PowerA MINI PROEX Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5303.kl b/data/keyboards/Vendor_24c6_Product_5303.kl new file mode 100644 index 000000000000..9e98aeec7b73 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5303.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Xbox Airflo wired controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_530a.kl b/data/keyboards/Vendor_24c6_Product_530a.kl new file mode 100644 index 000000000000..aa88515c0826 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_530a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Xbox 360 Pro EX Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_531a.kl b/data/keyboards/Vendor_24c6_Product_531a.kl new file mode 100644 index 000000000000..09a5c6a85c4f --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_531a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PowerA Pro Ex +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5397.kl b/data/keyboards/Vendor_24c6_Product_5397.kl new file mode 100644 index 000000000000..66b896a36d5f --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5397.kl @@ -0,0 +1,58 @@ +# 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. + +# +# FUS1ON Tournament Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_541a.kl b/data/keyboards/Vendor_24c6_Product_541a.kl new file mode 100644 index 000000000000..24271fbbba4b --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_541a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PowerA Xbox One Mini Wired Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_542a.kl b/data/keyboards/Vendor_24c6_Product_542a.kl new file mode 100644 index 000000000000..623bd1375b11 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_542a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Xbox ONE spectra +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_543a.kl b/data/keyboards/Vendor_24c6_Product_543a.kl new file mode 100644 index 000000000000..59769c4c0585 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_543a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PowerA Xbox One wired controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5500.kl b/data/keyboards/Vendor_24c6_Product_5500.kl new file mode 100644 index 000000000000..d76d7d08267b --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5500.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Hori XBOX 360 EX 2 with Turbo +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5501.kl b/data/keyboards/Vendor_24c6_Product_5501.kl new file mode 100644 index 000000000000..64d901af132b --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5501.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Hori Real Arcade Pro VX-SA +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5506.kl b/data/keyboards/Vendor_24c6_Product_5506.kl new file mode 100644 index 000000000000..bfb23c309029 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5506.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Hori SOULCALIBUR V Stick +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_550d.kl b/data/keyboards/Vendor_24c6_Product_550d.kl new file mode 100644 index 000000000000..24852b0bd867 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_550d.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Hori GEM Xbox controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_551a.kl b/data/keyboards/Vendor_24c6_Product_551a.kl new file mode 100644 index 000000000000..5e338a5c22f9 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_551a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PowerA FUSION Pro Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_561a.kl b/data/keyboards/Vendor_24c6_Product_561a.kl new file mode 100644 index 000000000000..57b7ddcca207 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_561a.kl @@ -0,0 +1,58 @@ +# 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. + +# +# PowerA FUSION Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5b02.kl b/data/keyboards/Vendor_24c6_Product_5b02.kl new file mode 100644 index 000000000000..bcf354d0e418 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5b02.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Thrustmaster, Inc. GPX Controller +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_5d04.kl b/data/keyboards/Vendor_24c6_Product_5d04.kl new file mode 100644 index 000000000000..39d8b2e6c1e2 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_5d04.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Razer Sabertooth +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/data/keyboards/Vendor_24c6_Product_fafe.kl b/data/keyboards/Vendor_24c6_Product_fafe.kl new file mode 100644 index 000000000000..f8d3f0c08009 --- /dev/null +++ b/data/keyboards/Vendor_24c6_Product_fafe.kl @@ -0,0 +1,58 @@ +# 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. + +# +# Rock Candy Gamepad for Xbox 360 +# Autogenerated based on Vendor_045e_Product_02ea.kl (XBox One Controller - Model 1708) +# + +# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y + +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt +# Two overlapping rectangles +key 314 BUTTON_SELECT +# Hamburger - 3 parallel lines +key 315 BUTTON_START + +# Xbox key +key 316 BUTTON_MODE diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java index 853165d4cf3f..b09082e65ca4 100644 --- a/graphics/java/android/graphics/fonts/Font.java +++ b/graphics/java/android/graphics/fonts/Font.java @@ -19,6 +19,7 @@ package android.graphics.fonts; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.content.res.Resources; import android.os.LocaleList; @@ -219,6 +220,27 @@ public final class Font { Preconditions.checkNotNull(am, "assetManager can not be null"); Preconditions.checkNotNull(path, "path can not be null"); + // Attempt to open as FD, which should work unless the asset is compressed + AssetFileDescriptor assetFD; + try { + if (isAsset) { + assetFD = am.openFd(path); + } else if (cookie > 0) { + assetFD = am.openNonAssetFd(cookie, path); + } else { + assetFD = am.openNonAssetFd(path); + } + + try (FileInputStream fis = assetFD.createInputStream()) { + final FileChannel fc = fis.getChannel(); + long startOffset = assetFD.getStartOffset(); + long declaredLength = assetFD.getDeclaredLength(); + return fc.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength); + } + } catch (IOException e) { + // failed to open as FD so now we will attempt to open as an input stream + } + try (InputStream assetStream = isAsset ? am.open(path, AssetManager.ACCESS_BUFFER) : am.openNonAsset(cookie, path, AssetManager.ACCESS_BUFFER)) { diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java index 8a7b62332ffa..f82d8b62e21e 100644 --- a/keystore/java/android/security/keystore/AttestationUtils.java +++ b/keystore/java/android/security/keystore/AttestationUtils.java @@ -74,7 +74,8 @@ public abstract class AttestationUtils { public static final int ID_TYPE_MEID = 3; /** - * Specifies that the device should attest its MEIDs. For use with {@link #attestDeviceIds}. + * Specifies that the device should sign the attestation record using its device-unique + * attestation certificate. For use with {@link #attestDeviceIds}. * * @see #attestDeviceIds */ diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 3f2f3495ae8f..f87f98a59a12 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -191,4 +191,3 @@ cc_benchmark { shared_libs: common_test_libs, data: ["tests/data/**/*.apk"], } - diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 35cebd425dc7..2bfc7fc38d1c 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -22,6 +22,7 @@ #include <androidfw/Asset.h> #include <androidfw/LocaleData.h> +#include <androidfw/StringPiece.h> #include <utils/Errors.h> #include <utils/String16.h> #include <utils/Vector.h> @@ -34,6 +35,7 @@ #include <android/configuration.h> +#include <array> #include <memory> namespace android { @@ -1676,42 +1678,64 @@ struct ResTable_overlayable_header */ struct ResTable_overlayable_policy_header { - struct ResChunk_header header; - + /** + * Flags for a bitmask for all possible overlayable policy options. + * + * Any changes to this set should also update aidl/android/os/OverlayablePolicy.aidl + */ enum PolicyFlags : uint32_t { + // Base + NONE = 0x00000000, + // Any overlay can overlay these resources. - POLICY_PUBLIC = 0x00000001, + PUBLIC = 0x00000001, // The overlay must reside of the system partition or must have existed on the system partition // before an upgrade to overlay these resources. - POLICY_SYSTEM_PARTITION = 0x00000002, + SYSTEM_PARTITION = 0x00000002, // The overlay must reside of the vendor partition or must have existed on the vendor partition // before an upgrade to overlay these resources. - POLICY_VENDOR_PARTITION = 0x00000004, + VENDOR_PARTITION = 0x00000004, // The overlay must reside of the product partition or must have existed on the product // partition before an upgrade to overlay these resources. - POLICY_PRODUCT_PARTITION = 0x00000008, + PRODUCT_PARTITION = 0x00000008, - // The overlay must be signed with the same signature as the actor of the target resource, - // which can be separate or the same as the target package with the resource. - POLICY_SIGNATURE = 0x00000010, + // The overlay must be signed with the same signature as the package containing the target + // resource + SIGNATURE = 0x00000010, // The overlay must reside of the odm partition or must have existed on the odm // partition before an upgrade to overlay these resources. - POLICY_ODM_PARTITION = 0x00000020, + ODM_PARTITION = 0x00000020, // The overlay must reside of the oem partition or must have existed on the oem // partition before an upgrade to overlay these resources. - POLICY_OEM_PARTITION = 0x00000040, + OEM_PARTITION = 0x00000040, + + // The overlay must be signed with the same signature as the actor declared for the target + // resource + ACTOR_SIGNATURE = 0x00000080, }; - uint32_t policy_flags; + + using PolicyBitmask = uint32_t; + + struct ResChunk_header header; + + PolicyFlags policy_flags; // The number of ResTable_ref that follow this header. uint32_t entry_count; }; +inline ResTable_overlayable_policy_header::PolicyFlags& operator |=( + ResTable_overlayable_policy_header::PolicyFlags& first, + ResTable_overlayable_policy_header::PolicyFlags second) { + first = static_cast<ResTable_overlayable_policy_header::PolicyFlags>(first | second); + return first; +} + #pragma pack(push, 1) struct Idmap_header { // Always 0x504D4449 ('IDMP') diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index 8615069e98dd..2d69dfe4f429 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -41,6 +41,8 @@ using ::testing::NotNull; using ::testing::SizeIs; using ::testing::StrEq; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace android { TEST(LoadedArscTest, LoadSinglePackageArsc) { @@ -240,29 +242,29 @@ TEST(LoadedArscTest, LoadOverlayable) { ASSERT_THAT(info, NotNull()); EXPECT_THAT(info->name, Eq("OverlayableResources1")); EXPECT_THAT(info->actor, Eq("overlay://theme")); - EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC)); + EXPECT_THAT(info->policy_flags, Eq(PolicyFlags::PUBLIC)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable2); ASSERT_THAT(info, NotNull()); EXPECT_THAT(info->name, Eq("OverlayableResources1")); EXPECT_THAT(info->actor, Eq("overlay://theme")); EXPECT_THAT(info->policy_flags, - Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION - | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION)); + Eq(PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable3); ASSERT_THAT(info, NotNull()); EXPECT_THAT(info->name, Eq("OverlayableResources2")); EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable")); EXPECT_THAT(info->policy_flags, - Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION - | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION)); + Eq(PolicyFlags::VENDOR_PARTITION + | PolicyFlags::PRODUCT_PARTITION)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable4); EXPECT_THAT(info->name, Eq("OverlayableResources1")); EXPECT_THAT(info->actor, Eq("overlay://theme")); ASSERT_THAT(info, NotNull()); - EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC)); + EXPECT_THAT(info->policy_flags, Eq(PolicyFlags::PUBLIC)); } TEST(LoadedArscTest, ResourceIdentifierIterator) { diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java index ca0bfb1added..27d363783a5a 100644 --- a/location/java/android/location/GnssNavigationMessage.java +++ b/location/java/android/location/GnssNavigationMessage.java @@ -272,6 +272,14 @@ public final class GnssNavigationMessage implements Parcelable { * range of 1-12</li> * <li> For Galileo I/NAV nominal frame structure, this refers to the subframe number in the * range of 1-24</li> + * <li> For SBAS and Beidou CNAV2, this is unused and can be set to -1.</li> + * <li> For QZSS L1 C/A subframe 4 and 5, this value corresponds to the 'frame id' of the + * navigation message, in the range of 1-25 (Subframe 1, 2, 3 does not contain a 'frame id' and + * this value can be set to -1.)</li> + * <li> For Beidou CNAV1 this refers to the page type number in the range of 1-63.</li> + * <li> For IRNSS L5 C/A subframe 3 and 4, this value corresponds to the Message Id of the + * navigation message, in the range of 1-63. (Subframe 1 and 2 does not contain a message type + * id and this value can be set to -1.)</li> * </ul> */ public int getMessageId() { @@ -299,6 +307,13 @@ public final class GnssNavigationMessage implements Parcelable { * <li>For Galileo in particular, the type information embedded within the data bits may be even * more useful in interpretation, than the nominal page and word types provided in this * field.</li> + * <li> For SBAS, the submessage id corresponds to the message type, in the range 1-63.</li> + * <li> For Beidou CNAV1, the submessage id corresponds to the subframe number of the + * navigation message, in the range of 1-3.</li> + * <li> For Beidou CNAV2, the submessage id corresponds to the message type, in the range + * 1-63.</li> + * <li> For IRNSS L5 C/A, the submessage id corresponds to the subframe number of the + * navigation message, in the range of 1-4.</li> * </ul> */ public int getSubmessageId() { @@ -333,6 +348,13 @@ public final class GnssNavigationMessage implements Parcelable { * <li>For Galileo I/NAV, each page contains 2 page parts, even and odd, with a total of 2x114 = * 228 bits, (sync & tail excluded) that should be fit into 29 bytes, with MSB first (skip * B229-B232).</li> + * <li>For SBAS, each block consists of 250 data bits, that should be fit into 32 bytes. MSB + * first (skip B251-B256).</li> + * <li>For Beidou CNAV1, subframe #1 consists of 14 data bits, that should be fit into 2 + * bytes. MSB first (skip B15-B16). subframe #2 consists of 600 bits that should be fit into + * 75 bytes. subframe #3 consists of 264 data bits that should be fit into 33 bytes.</li> + * <li>For Beidou CNAV2, each subframe consists of 288 data bits, that should be fit into 36 + * bytes.</li> * </ul> */ @NonNull diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index f2b4db1afdac..f800f9ee91c9 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -2531,7 +2531,7 @@ final public class MediaCodec { int offset, int size, long presentationTimeUs, int flags) throws CryptoException { synchronized(mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } invalidateByteBuffer(mCachedInputBuffers, index); @@ -2783,7 +2783,7 @@ final public class MediaCodec { long presentationTimeUs, int flags) throws CryptoException { synchronized(mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } invalidateByteBuffer(mCachedInputBuffers, index); @@ -2818,7 +2818,7 @@ final public class MediaCodec { */ public final int dequeueInputBuffer(long timeoutUs) { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } } @@ -3534,7 +3534,7 @@ final public class MediaCodec { public final int dequeueOutputBuffer( @NonNull BufferInfo info, long timeoutUs) { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } } @@ -3916,7 +3916,7 @@ final public class MediaCodec { @NonNull public ByteBuffer[] getInputBuffers() { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } if (mCachedInputBuffers == null) { @@ -3952,7 +3952,7 @@ final public class MediaCodec { @NonNull public ByteBuffer[] getOutputBuffers() { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } if (mCachedOutputBuffers == null) { @@ -3984,7 +3984,7 @@ final public class MediaCodec { @Nullable public ByteBuffer getInputBuffer(int index) { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } } @@ -4018,7 +4018,7 @@ final public class MediaCodec { @Nullable public Image getInputImage(int index) { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } } @@ -4052,7 +4052,7 @@ final public class MediaCodec { @Nullable public ByteBuffer getOutputBuffer(int index) { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } } @@ -4085,7 +4085,7 @@ final public class MediaCodec { @Nullable public Image getOutputImage(int index) { synchronized (mBufferLock) { - if (mBufferMode != BUFFER_MODE_LEGACY) { + if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException(); } } diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 34109194acba..fd2408935fff 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -749,7 +749,7 @@ public class MediaRouter2 { /** * Callback for receiving events about media route discovery. */ - public static class RouteCallback { + public abstract static class RouteCallback { /** * Called when routes are added. Whenever you registers a callback, this will * be invoked with known routes. @@ -777,7 +777,7 @@ public class MediaRouter2 { /** * Callback for receiving events on media transfer. */ - public static class TransferCallback { + public abstract static class TransferCallback { /** * Called when a media is transferred between two different routing controllers. * This can happen by calling {@link #transferTo(MediaRoute2Info)} or @@ -826,7 +826,7 @@ public class MediaRouter2 { /** * Callback for receiving {@link RoutingController} updates. */ - public static class ControllerCallback { + public abstract static class ControllerCallback { /** * Called when a controller is updated. (e.g., the selected routes of the * controller is changed or the volume of the controller is changed.) @@ -1071,7 +1071,7 @@ public class MediaRouter2 { try { mMediaRouterService.deselectRouteWithRouter2(stub, getId(), route); } catch (RemoteException ex) { - Log.e(TAG, "Unable to remove route from session.", ex); + Log.e(TAG, "Unable to deselect route from session.", ex); } } } diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index ff2c863aa7b0..fb45ae170461 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -44,8 +44,10 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** + * A class that monitors and controls media routing of other apps. * @hide */ public class MediaRouter2Manager { @@ -201,10 +203,24 @@ public class MediaRouter2Manager { } /** + * Gets the system routing session associated with no specific application. + */ + @NonNull + public RoutingSessionInfo getSystemRoutingSession() { + for (RoutingSessionInfo sessionInfo : getActiveSessions()) { + if (sessionInfo.isSystemSession()) { + return sessionInfo; + } + } + throw new IllegalStateException("No system routing session"); + } + + /** * Gets routing sessions of an application with the given package name. - * The first element of the returned list is the system routing controller. + * The first element of the returned list is the system routing session. * - * @see MediaRouter2#getSystemController() + * @param packageName the package name of the application that is routing. + * @see #getSystemRoutingSession() */ @NonNull public List<RoutingSessionInfo> getRoutingSessions(@NonNull String packageName) { @@ -213,8 +229,11 @@ public class MediaRouter2Manager { List<RoutingSessionInfo> sessions = new ArrayList<>(); for (RoutingSessionInfo sessionInfo : getActiveSessions()) { - if (sessionInfo.isSystemSession() - || TextUtils.equals(sessionInfo.getClientPackageName(), packageName)) { + if (sessionInfo.isSystemSession()) { + sessions.add(new RoutingSessionInfo.Builder(sessionInfo) + .setClientPackageName(packageName) + .build()); + } else if (TextUtils.equals(sessionInfo.getClientPackageName(), packageName)) { sessions.add(sessionInfo); } } @@ -223,10 +242,15 @@ public class MediaRouter2Manager { /** * Gets the list of all active routing sessions. + * <p> * The first element of the list is the system routing session containing * phone speakers, wired headset, Bluetooth devices. * The system routing session is shared by apps such that controlling it will affect * all apps. + * If you want to transfer media of an application, use {@link #getRoutingSessions(String)}. + * + * @see #getRoutingSessions(String) + * @see #getSystemRoutingSession() */ @NonNull public List<RoutingSessionInfo> getActiveSessions() { @@ -258,31 +282,46 @@ public class MediaRouter2Manager { /** * Selects media route for the specified package name. - * - * If the given route is {@link RoutingController#getTransferableRoutes() a transferable - * route} of a routing session of the application, the session will be transferred to - * the route. If not, a new routing session will be created. - * - * @param packageName the package name of the application that should change it's media route - * @param route the route to be selected. */ public void selectRoute(@NonNull String packageName, @NonNull MediaRoute2Info route) { Objects.requireNonNull(packageName, "packageName must not be null"); Objects.requireNonNull(route, "route must not be null"); - boolean transferred = false; - //TODO: instead of release all controllers, add an API to specify controllers that - // should be released (or is the system controller). - for (RoutingSessionInfo sessionInfo : getRoutingSessions(packageName)) { - if (!transferred && sessionInfo.getTransferableRoutes().contains(route.getId())) { - new RoutingController(sessionInfo).transferToRoute(route); - transferred = true; - } else if (!sessionInfo.isSystemSession()) { - new RoutingController(sessionInfo).release(); - } + List<RoutingSessionInfo> sessionInfos = getRoutingSessions(packageName); + RoutingSessionInfo targetSession = sessionInfos.get(sessionInfos.size() - 1); + transfer(targetSession, route); + } + + /** + * Transfers a routing session to a media route. + * <p>{@link Callback#onTransferred} or {@link Callback#onTransferFailed} will be called + * depending on the result. + * + * @param sessionInfo the routing session info to transfer + * @param route the route transfer to + * + * @see Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo) + * @see Callback#onTransferFailed(RoutingSessionInfo, MediaRoute2Info) + */ + public void transfer(@NonNull RoutingSessionInfo sessionInfo, + @Nullable MediaRoute2Info route) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + + if (route == null) { + releaseSession(sessionInfo); + return; } - if (transferred) { + //TODO: Ignore unknown route. + if (sessionInfo.getTransferableRoutes().contains(route.getId())) { + //TODO: callbacks must be called after this. + transferToRoute(sessionInfo, route); + return; + } + + if (TextUtils.isEmpty(sessionInfo.getClientPackageName())) { + Log.w(TAG, "transfer: Ignoring transfer without package name."); + notifyTransferFailed(sessionInfo, route); return; } @@ -294,7 +333,7 @@ public class MediaRouter2Manager { try { int requestId = mNextRequestId.getAndIncrement(); mMediaRouterService.requestCreateSessionWithManager( - client, packageName, route, requestId); + client, sessionInfo.getClientPackageName(), route, requestId); //TODO: release the previous session? } catch (RemoteException ex) { Log.e(TAG, "Unable to select media route", ex); @@ -451,6 +490,18 @@ public class MediaRouter2Manager { } } + void notifyTransferred(RoutingSessionInfo oldSession, RoutingSessionInfo newSession) { + for (CallbackRecord record : mCallbackRecords) { + record.mExecutor.execute(() -> record.mCallback.onTransferred(oldSession, newSession)); + } + } + + void notifyTransferFailed(RoutingSessionInfo sessionInfo, MediaRoute2Info route) { + for (CallbackRecord record : mCallbackRecords) { + record.mExecutor.execute(() -> record.mCallback.onTransferFailed(sessionInfo, route)); + } + } + void updatePreferredFeatures(String packageName, List<String> preferredFeatures) { List<String> prevFeatures = mPreferredFeaturesMap.put(packageName, preferredFeatures); if ((prevFeatures == null && preferredFeatures.size() == 0) @@ -475,6 +526,204 @@ public class MediaRouter2Manager { } /** + * Gets the unmodifiable list of selected routes for the session. + */ + @NonNull + public List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo sessionInfo) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + + List<String> routeIds = sessionInfo.getSelectedRoutes(); + return getRoutesWithIds(routeIds); + } + + /** + * Gets the unmodifiable list of selectable routes for the session. + */ + @NonNull + public List<MediaRoute2Info> getSelectableRoutes(@NonNull RoutingSessionInfo sessionInfo) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + + List<String> routeIds = sessionInfo.getSelectableRoutes(); + return getRoutesWithIds(routeIds); + } + + /** + * Gets the unmodifiable list of deselectable routes for the session. + */ + @NonNull + public List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo sessionInfo) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + + List<String> routeIds = sessionInfo.getDeselectableRoutes(); + return getRoutesWithIds(routeIds); + } + + /** + * Selects a route for the remote session. After a route is selected, the media is expected + * to be played to the all the selected routes. This is different from {@link + * #transfer(RoutingSessionInfo, MediaRoute2Info)} transferring to a route}, + * where the media is expected to 'move' from one route to another. + * <p> + * The given route must satisfy all of the following conditions: + * <ul> + * <li>it should not be included in {@link #getSelectedRoutes(RoutingSessionInfo)}</li> + * <li>it should be included in {@link #getSelectableRoutes(RoutingSessionInfo)}</li> + * </ul> + * If the route doesn't meet any of above conditions, it will be ignored. + * + * @see #getSelectedRoutes(RoutingSessionInfo) + * @see #getSelectableRoutes(RoutingSessionInfo) + * @see Callback#onSessionsUpdated() + */ + public void selectRoute(@NonNull RoutingSessionInfo sessionInfo, + @NonNull MediaRoute2Info route) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + Objects.requireNonNull(route, "route must not be null"); + + if (sessionInfo.getSelectedRoutes().contains(route.getId())) { + Log.w(TAG, "Ignoring selecting a route that is already selected. route=" + route); + return; + } + + if (!sessionInfo.getSelectableRoutes().contains(route.getId())) { + Log.w(TAG, "Ignoring selecting a non-selectable route=" + route); + return; + } + + Client client; + synchronized (sLock) { + client = mClient; + } + if (client != null) { + try { + int requestId = mNextRequestId.getAndIncrement(); + mMediaRouterService.selectRouteWithManager( + mClient, sessionInfo.getId(), route, requestId); + } catch (RemoteException ex) { + Log.e(TAG, "selectRoute: Failed to send a request.", ex); + } + } + } + + /** + * Deselects a route from the remote session. After a route is deselected, the media is + * expected to be stopped on the deselected routes. + * <p> + * The given route must satisfy all of the following conditions: + * <ul> + * <li>it should be included in {@link #getSelectedRoutes(RoutingSessionInfo)}</li> + * <li>it should be included in {@link #getDeselectableRoutes(RoutingSessionInfo)}</li> + * </ul> + * If the route doesn't meet any of above conditions, it will be ignored. + * + * @see #getSelectedRoutes(RoutingSessionInfo) + * @see #getDeselectableRoutes(RoutingSessionInfo) + * @see Callback#onSessionsUpdated() + */ + public void deselectRoute(@NonNull RoutingSessionInfo sessionInfo, + @NonNull MediaRoute2Info route) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + Objects.requireNonNull(route, "route must not be null"); + + if (!sessionInfo.getSelectedRoutes().contains(route.getId())) { + Log.w(TAG, "Ignoring deselecting a route that is not selected. route=" + route); + return; + } + + if (!sessionInfo.getDeselectableRoutes().contains(route.getId())) { + Log.w(TAG, "Ignoring deselecting a non-deselectable route=" + route); + return; + } + + Client client; + synchronized (sLock) { + client = mClient; + } + if (client != null) { + try { + int requestId = mNextRequestId.getAndIncrement(); + mMediaRouterService.deselectRouteWithManager( + mClient, sessionInfo.getId(), route, requestId); + } catch (RemoteException ex) { + Log.e(TAG, "deselectRoute: Failed to send a request.", ex); + } + } + } + + /** + * Transfers to a given route for the remote session. + * + * @hide + */ + void transferToRoute(@NonNull RoutingSessionInfo sessionInfo, + @NonNull MediaRoute2Info route) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + Objects.requireNonNull(route, "route must not be null"); + + if (sessionInfo.getSelectedRoutes().contains(route.getId())) { + Log.w(TAG, "Ignoring transferring to a route that is already added. route=" + + route); + return; + } + + if (!sessionInfo.getTransferableRoutes().contains(route.getId())) { + Log.w(TAG, "Ignoring transferring to a non-transferable route=" + route); + return; + } + + Client client; + synchronized (sLock) { + client = mClient; + } + if (client != null) { + try { + int requestId = mNextRequestId.getAndIncrement(); + mMediaRouterService.transferToRouteWithManager( + mClient, sessionInfo.getId(), route, requestId); + } catch (RemoteException ex) { + Log.e(TAG, "transferToRoute: Failed to send a request.", ex); + } + } + } + + /** + * Requests releasing a session. + * <p> + * If a session is released, any operation on the session will be ignored. + * {@link Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo)} with {@code null} + * session will be called when the session is released. + * </p> + * + * @see Callback#onTransferred(RoutingSessionInfo, RoutingSessionInfo) + */ + public void releaseSession(@NonNull RoutingSessionInfo sessionInfo) { + Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + + Client client; + synchronized (sLock) { + client = mClient; + } + if (client != null) { + try { + int requestId = mNextRequestId.getAndIncrement(); + mMediaRouterService.releaseSessionWithManager( + mClient, sessionInfo.getId(), requestId); + } catch (RemoteException ex) { + Log.e(TAG, "releaseSession: Failed to send a request", ex); + } + } + } + + private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) { + synchronized (sLock) { + return routeIds.stream().map(mRoutes::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + } + + //TODO: Remove this. + /** * A class to control media routing session in media route provider. * With routing controller, an application can select a route into the session or deselect * a route in the session. @@ -489,6 +738,15 @@ public class MediaRouter2Manager { } /** + * Releases the session + */ + public void release() { + synchronized (mControllerLock) { + releaseSession(mSessionInfo); + } + } + + /** * Gets the ID of the session */ @NonNull @@ -523,11 +781,7 @@ public class MediaRouter2Manager { */ @NonNull public List<MediaRoute2Info> getSelectedRoutes() { - List<String> routeIds; - synchronized (mControllerLock) { - routeIds = mSessionInfo.getSelectedRoutes(); - } - return getRoutesWithIds(routeIds); + return MediaRouter2Manager.this.getSelectedRoutes(mSessionInfo); } /** @@ -535,11 +789,7 @@ public class MediaRouter2Manager { */ @NonNull public List<MediaRoute2Info> getSelectableRoutes() { - List<String> routeIds; - synchronized (mControllerLock) { - routeIds = mSessionInfo.getSelectableRoutes(); - } - return getRoutesWithIds(routeIds); + return MediaRouter2Manager.this.getSelectableRoutes(mSessionInfo); } /** @@ -547,11 +797,7 @@ public class MediaRouter2Manager { */ @NonNull public List<MediaRoute2Info> getDeselectableRoutes() { - List<String> routeIds; - synchronized (mControllerLock) { - routeIds = mSessionInfo.getDeselectableRoutes(); - } - return getRoutesWithIds(routeIds); + return MediaRouter2Manager.this.getDeselectableRoutes(mSessionInfo); } /** @@ -579,35 +825,7 @@ public class MediaRouter2Manager { * @see #getSelectableRoutes() */ public void selectRoute(@NonNull MediaRoute2Info route) { - Objects.requireNonNull(route, "route must not be null"); - - RoutingSessionInfo sessionInfo; - synchronized (mControllerLock) { - sessionInfo = mSessionInfo; - } - if (sessionInfo.getSelectedRoutes().contains(route.getId())) { - Log.w(TAG, "Ignoring selecting a route that is already selected. route=" + route); - return; - } - - if (!sessionInfo.getSelectableRoutes().contains(route.getId())) { - Log.w(TAG, "Ignoring selecting a non-selectable route=" + route); - return; - } - - Client client; - synchronized (sLock) { - client = mClient; - } - if (client != null) { - try { - int requestId = mNextRequestId.getAndIncrement(); - mMediaRouterService.selectRouteWithManager( - mClient, getSessionId(), route, requestId); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to select route for session.", ex); - } - } + MediaRouter2Manager.this.selectRoute(mSessionInfo, route); } /** @@ -623,104 +841,19 @@ public class MediaRouter2Manager { * @see #getDeselectableRoutes() */ public void deselectRoute(@NonNull MediaRoute2Info route) { - Objects.requireNonNull(route, "route must not be null"); - RoutingSessionInfo sessionInfo; - synchronized (mControllerLock) { - sessionInfo = mSessionInfo; - } - - if (!sessionInfo.getSelectedRoutes().contains(route.getId())) { - Log.w(TAG, "Ignoring deselecting a route that is not selected. route=" + route); - return; - } - - if (!sessionInfo.getDeselectableRoutes().contains(route.getId())) { - Log.w(TAG, "Ignoring deselecting a non-deselectable route=" + route); - return; - } - - Client client; - synchronized (sLock) { - client = mClient; - } - if (client != null) { - try { - int requestId = mNextRequestId.getAndIncrement(); - mMediaRouterService.deselectRouteWithManager( - mClient, getSessionId(), route, requestId); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to remove route from session.", ex); - } - } + MediaRouter2Manager.this.deselectRoute(mSessionInfo, route); } /** - * Transfers to a given route for the remote session. The given route must satisfy - * all of the following conditions: - * <ul> - * <li>ID should not be included in {@link #getSelectedRoutes()}</li> - * <li>ID should be included in {@link #getTransferableRoutes()}</li> - * </ul> - * If the route doesn't meet any of above conditions, it will be ignored. - * - * @see #getSelectedRoutes() - * @see #getTransferableRoutes() + * Transfers session to the given rotue. */ public void transferToRoute(@NonNull MediaRoute2Info route) { - Objects.requireNonNull(route, "route must not be null"); - RoutingSessionInfo sessionInfo; - synchronized (mControllerLock) { - sessionInfo = mSessionInfo; - } - - if (sessionInfo.getSelectedRoutes().contains(route.getId())) { - Log.w(TAG, "Ignoring transferring to a route that is already added. route=" - + route); - return; - } - - if (!sessionInfo.getTransferableRoutes().contains(route.getId())) { - Log.w(TAG, "Ignoring transferring to a non-transferable route=" + route); - return; - } - - Client client; - synchronized (sLock) { - client = mClient; - } - if (client != null) { - try { - int requestId = mNextRequestId.getAndIncrement(); - mMediaRouterService.transferToRouteWithManager( - mClient, getSessionId(), route, requestId); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to transfer to route for session.", ex); - } - } - } - - /** - * Release this session. - * Any operation on this session after calling this method will be ignored. - */ - public void release() { - Client client; - synchronized (sLock) { - client = mClient; - } - if (client != null) { - try { - int requestId = mNextRequestId.getAndIncrement(); - mMediaRouterService.releaseSessionWithManager( - mClient, getSessionId(), requestId); - } catch (RemoteException ex) { - Log.e(TAG, "Unable to notify of controller release", ex); - } - } + MediaRouter2Manager.this.transferToRoute(mSessionInfo, route); } /** * Gets the session info of the session + * * @hide */ @NonNull @@ -729,19 +862,6 @@ public class MediaRouter2Manager { return mSessionInfo; } } - - private List<MediaRoute2Info> getRoutesWithIds(List<String> routeIds) { - List<MediaRoute2Info> routes = new ArrayList<>(); - synchronized (mRoutesLock) { - for (String routeId : routeIds) { - MediaRoute2Info route = mRoutes.get(routeId); - if (route != null) { - routes.add(route); - } - } - } - return Collections.unmodifiableList(routes); - } } /** @@ -780,7 +900,24 @@ public class MediaRouter2Manager { */ public void onSessionsUpdated() {} - //TODO: remove this + //TODO: Call this. + /** + * Called when media is transferred. + * + * @param oldSession the previous session + * @param newSession the new session or {@code null} if the session is released. + */ + public void onTransferred(@NonNull RoutingSessionInfo oldSession, + @Nullable RoutingSessionInfo newSession) { } + + //TODO: Call this. + /** + * Called when {@link #transfer(RoutingSessionInfo, MediaRoute2Info)} fails. + */ + public void onTransferFailed(@NonNull RoutingSessionInfo session, + @NonNull MediaRoute2Info route) { } + + //TODO: Remove this. /** * Called when the preferred route features of an app is changed. * diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java index 19a46ce6570d..2276b6aba770 100644 --- a/media/java/android/media/RoutingSessionInfo.java +++ b/media/java/android/media/RoutingSessionInfo.java @@ -49,6 +49,7 @@ public final class RoutingSessionInfo implements Parcelable { private static final String TAG = "RoutingSessionInfo"; final String mId; + final CharSequence mName; final String mClientPackageName; @Nullable final String mProviderId; @@ -69,6 +70,7 @@ public final class RoutingSessionInfo implements Parcelable { Objects.requireNonNull(builder, "builder must not be null."); mId = builder.mId; + mName = builder.mName; mClientPackageName = builder.mClientPackageName; mProviderId = builder.mProviderId; @@ -94,6 +96,7 @@ public final class RoutingSessionInfo implements Parcelable { Objects.requireNonNull(src, "src must not be null."); mId = ensureString(src.readString()); + mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src); mClientPackageName = ensureString(src.readString()); mProviderId = src.readString(); @@ -111,10 +114,7 @@ public final class RoutingSessionInfo implements Parcelable { } private static String ensureString(String str) { - if (str != null) { - return str; - } - return ""; + return str != null ? str : ""; } private static <T> List<T> ensureList(List<? extends T> list) { @@ -143,6 +143,14 @@ public final class RoutingSessionInfo implements Parcelable { } /** + * Gets the user-visible name of the session. It may be {@code null}. + */ + @Nullable + public CharSequence getName() { + return mName; + } + + /** * Gets the original id set by {@link Builder#Builder(String, String)}. * @hide */ @@ -169,7 +177,7 @@ public final class RoutingSessionInfo implements Parcelable { } /** - * Gets the list of ids of selected routes for the session. It shouldn't be empty. + * Gets the list of IDs of selected routes for the session. It shouldn't be empty. */ @NonNull public List<String> getSelectedRoutes() { @@ -177,7 +185,7 @@ public final class RoutingSessionInfo implements Parcelable { } /** - * Gets the list of ids of selectable routes for the session. + * Gets the list of IDs of selectable routes for the session. */ @NonNull public List<String> getSelectableRoutes() { @@ -185,7 +193,7 @@ public final class RoutingSessionInfo implements Parcelable { } /** - * Gets the list of ids of deselectable routes for the session. + * Gets the list of IDs of deselectable routes for the session. */ @NonNull public List<String> getDeselectableRoutes() { @@ -193,7 +201,7 @@ public final class RoutingSessionInfo implements Parcelable { } /** - * Gets the list of ids of transferable routes for the session. + * Gets the list of IDs of transferable routes for the session. */ @NonNull public List<String> getTransferableRoutes() { @@ -255,6 +263,7 @@ public final class RoutingSessionInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(mId); + dest.writeCharSequence(mName); dest.writeString(mClientPackageName); dest.writeString(mProviderId); dest.writeStringList(mSelectedRoutes); @@ -279,6 +288,7 @@ public final class RoutingSessionInfo implements Parcelable { RoutingSessionInfo other = (RoutingSessionInfo) obj; return Objects.equals(mId, other.mId) + && Objects.equals(mName, other.mName) && Objects.equals(mClientPackageName, other.mClientPackageName) && Objects.equals(mProviderId, other.mProviderId) && Objects.equals(mSelectedRoutes, other.mSelectedRoutes) @@ -292,7 +302,7 @@ public final class RoutingSessionInfo implements Parcelable { @Override public int hashCode() { - return Objects.hash(mId, mClientPackageName, mProviderId, + return Objects.hash(mId, mName, mClientPackageName, mProviderId, mSelectedRoutes, mSelectableRoutes, mDeselectableRoutes, mTransferableRoutes, mVolumeMax, mVolumeHandling, mVolume); } @@ -302,6 +312,7 @@ public final class RoutingSessionInfo implements Parcelable { StringBuilder result = new StringBuilder() .append("RoutingSessionInfo{ ") .append("sessionId=").append(mId) + .append(", name=").append(mName) .append(", selectedRoutes={") .append(String.join(",", mSelectedRoutes)) .append("}") @@ -345,7 +356,8 @@ public final class RoutingSessionInfo implements Parcelable { public static final class Builder { // TODO: Reorder these (important ones first) final String mId; - final String mClientPackageName; + CharSequence mName; + String mClientPackageName; String mProviderId; final List<String> mSelectedRoutes; final List<String> mSelectableRoutes; @@ -357,6 +369,7 @@ public final class RoutingSessionInfo implements Parcelable { Bundle mControlHints; boolean mIsSystemSession; + //TODO: Remove this. /** * Constructor for builder to create {@link RoutingSessionInfo}. * <p> @@ -374,10 +387,10 @@ public final class RoutingSessionInfo implements Parcelable { if (TextUtils.isEmpty(id)) { throw new IllegalArgumentException("id must not be empty"); } - Objects.requireNonNull(clientPackageName, "clientPackageName must not be null"); mId = id; - mClientPackageName = clientPackageName; + mClientPackageName = + Objects.requireNonNull(clientPackageName, "clientPackageName must not be null"); mSelectedRoutes = new ArrayList<>(); mSelectableRoutes = new ArrayList<>(); mDeselectableRoutes = new ArrayList<>(); @@ -394,6 +407,7 @@ public final class RoutingSessionInfo implements Parcelable { Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); mId = sessionInfo.mId; + mName = sessionInfo.mName; mClientPackageName = sessionInfo.mClientPackageName; mProviderId = sessionInfo.mProviderId; @@ -411,6 +425,26 @@ public final class RoutingSessionInfo implements Parcelable { } /** + * Sets the user-visible name of the session. + */ + @NonNull + public Builder setName(@Nullable CharSequence name) { + mName = name; + return this; + } + + /** + * Sets the client package name of the session. + * + * @hide + */ + @NonNull + public Builder setClientPackageName(@Nullable String packageName) { + mClientPackageName = packageName; + return this; + } + + /** * Sets the provider ID of the session. * * @hide diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 486c0c25a737..8bf462c5a5cf 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -196,7 +196,7 @@ public final class MediaSession { .getSystemService(Context.MEDIA_SESSION_SERVICE); try { mBinder = manager.createSession(mCbStub, tag, sessionInfo); - mSessionToken = new Token(mBinder.getController()); + mSessionToken = new Token(Process.myUid(), mBinder.getController()); mController = new MediaController(context, mSessionToken); } catch (RemoteException e) { throw new RuntimeException("Remote error creating session.", e); @@ -771,8 +771,8 @@ public final class MediaSession { /** * @hide */ - public Token(ISessionController binder) { - mUid = Process.myUid(); + public Token(int uid, ISessionController binder) { + mUid = uid; mBinder = binder; } diff --git a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl b/media/java/android/media/soundtrigger_middleware/SoundModel.aidl index fba1ee507836..81d8291e85aa 100644 --- a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl +++ b/media/java/android/media/soundtrigger_middleware/SoundModel.aidl @@ -32,5 +32,7 @@ parcelable SoundModel { * was build for */ String vendorUuid; /** Opaque data transparent to Android framework */ - byte[] data; + FileDescriptor data; + /** Size of the above data, in bytes. */ + int dataSize; } diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index b579144b45e8..95199cc8e045 100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -240,7 +240,7 @@ public abstract class TvInputService extends Service { * @param inputId The ID of the TV input associated with the session. */ @Nullable - public abstract Session onCreateSession(String inputId); + public abstract Session onCreateSession(@NonNull String inputId); /** * Returns a concrete implementation of {@link RecordingSession}. @@ -251,7 +251,7 @@ public abstract class TvInputService extends Service { * @param inputId The ID of the TV input associated with the recording session. */ @Nullable - public RecordingSession onCreateRecordingSession(String inputId) { + public RecordingSession onCreateRecordingSession(@NonNull String inputId) { return null; } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 73769be3d6ad..c79e72d86823 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -18,11 +18,13 @@ package android.media.tv.tuner; import android.annotation.BytesLong; import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; +import android.hardware.tv.tuner.V1_0.Constants; import android.media.tv.TvInputService; import android.media.tv.tuner.TunerConstants.Result; import android.media.tv.tuner.dvr.DvrPlayback; @@ -45,6 +47,8 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; @@ -67,6 +71,22 @@ public class Tuner implements AutoCloseable { private static final int MSG_ON_FILTER_STATUS = 3; private static final int MSG_ON_LNB_EVENT = 4; + /** @hide */ + @IntDef(prefix = "DVR_TYPE_", value = {DVR_TYPE_RECORD, DVR_TYPE_PLAYBACK}) + @Retention(RetentionPolicy.SOURCE) + public @interface DvrType {} + + /** + * DVR for recording. + * @hide + */ + public static final int DVR_TYPE_RECORD = Constants.DvrType.RECORD; + /** + * DVR for playback of recorded programs. + * @hide + */ + public static final int DVR_TYPE_PLAYBACK = Constants.DvrType.PLAYBACK; + static { System.loadLibrary("media_tv_tuner"); nativeInit(); @@ -196,8 +216,8 @@ public class Tuner implements AutoCloseable { private native int nativeSetLnb(int lnbId); private native int nativeSetLna(boolean enable); private native FrontendStatus nativeGetFrontendStatus(int[] statusTypes); - private native int nativeGetAvSyncHwId(Filter filter); - private native long nativeGetAvSyncTime(int avSyncId); + private native Integer nativeGetAvSyncHwId(Filter filter); + private native Long nativeGetAvSyncTime(int avSyncId); private native int nativeConnectCiCam(int ciCamId); private native int nativeDisconnectCiCam(); private native FrontendInfo nativeGetFrontendInfo(int id); @@ -443,7 +463,8 @@ public class Tuner implements AutoCloseable { @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int getAvSyncHwId(@NonNull Filter filter) { TunerUtils.checkTunerPermission(mContext); - return nativeGetAvSyncHwId(filter); + Integer id = nativeGetAvSyncHwId(filter); + return id == null ? TunerConstants.INVALID_AV_SYNC_ID : id; } /** @@ -458,7 +479,8 @@ public class Tuner implements AutoCloseable { @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public long getAvSyncTime(int avSyncHwId) { TunerUtils.checkTunerPermission(mContext); - return nativeGetAvSyncTime(avSyncHwId); + Long time = nativeGetAvSyncTime(avSyncHwId); + return time == null ? TunerConstants.TIMESTAMP_UNAVAILABLE : time; } /** diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java index 82af658af2ca..6d89962d190f 100644 --- a/media/java/android/media/tv/tuner/TunerConstants.java +++ b/media/java/android/media/tv/tuner/TunerConstants.java @@ -46,6 +46,19 @@ public final class TunerConstants { * Invalid AV Sync ID. */ public static final int INVALID_AV_SYNC_ID = Constants.Constant.INVALID_AV_SYNC_ID; + /** + * Timestamp is unavailable. + * + * <p>Returned by {@link android.media.tv.tuner.filter.TimeFilter#getSourceTime()}, + * {@link android.media.tv.tuner.filter.TimeFilter#getTimeStamp()}, or + * {@link Tuner#getAvSyncTime(int)} when the requested timestamp is not available. + * + * @see android.media.tv.tuner.filter.TimeFilter#getSourceTime() + * @see android.media.tv.tuner.filter.TimeFilter#getTimeStamp() + * @see Tuner#getAvSyncTime(int) + * @hide + */ + public static final long TIMESTAMP_UNAVAILABLE = -1L; /** @hide */ @IntDef(prefix = "SCAN_TYPE_", value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_AUTO, SCAN_TYPE_BLIND}) diff --git a/media/java/android/media/tv/tuner/dvr/Dvr.java b/media/java/android/media/tv/tuner/dvr/Dvr.java deleted file mode 100644 index 4183e3bbe640..000000000000 --- a/media/java/android/media/tv/tuner/dvr/Dvr.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media.tv.tuner.dvr; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.hardware.tv.tuner.V1_0.Constants; -import android.media.tv.tuner.TunerConstants.Result; -import android.media.tv.tuner.filter.Filter; -import android.os.ParcelFileDescriptor; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Digital Video Record (DVR) interface provides record control on Demux's output buffer and - * playback control on Demux's input buffer. - * - * @hide - */ -@SystemApi -public class Dvr implements AutoCloseable { - - /** @hide */ - @IntDef(prefix = "TYPE_", value = {TYPE_RECORD, TYPE_PLAYBACK}) - @Retention(RetentionPolicy.SOURCE) - public @interface Type {} - - /** - * DVR for recording. - */ - public static final int TYPE_RECORD = Constants.DvrType.RECORD; - /** - * DVR for playback of recorded programs. - */ - public static final int TYPE_PLAYBACK = Constants.DvrType.PLAYBACK; - - - final int mType; - long mNativeContext; - - private native int nativeAttachFilter(Filter filter); - private native int nativeDetachFilter(Filter filter); - private native int nativeConfigureDvr(DvrSettings settings); - private native int nativeStartDvr(); - private native int nativeStopDvr(); - private native int nativeFlushDvr(); - private native int nativeClose(); - private native void nativeSetFileDescriptor(int fd); - - protected Dvr(int type) { - mType = type; - } - - /** - * Attaches a filter to DVR interface for recording. - * - * @param filter the filter to be attached. - * @return result status of the operation. - */ - @Result - public int attachFilter(@NonNull Filter filter) { - return nativeAttachFilter(filter); - } - - /** - * Detaches a filter from DVR interface. - * - * @param filter the filter to be detached. - * @return result status of the operation. - */ - @Result - public int detachFilter(@NonNull Filter filter) { - return nativeDetachFilter(filter); - } - - /** - * Configures the DVR. - * - * @param settings the settings of the DVR interface. - * @return result status of the operation. - */ - @Result - public int configure(@NonNull DvrSettings settings) { - return nativeConfigureDvr(settings); - } - - /** - * Starts DVR. - * - * <p>Starts consuming playback data or producing data for recording. - * - * @return result status of the operation. - */ - @Result - public int start() { - return nativeStartDvr(); - } - - /** - * Stops DVR. - * - * <p>Stops consuming playback data or producing data for recording. - * - * @return result status of the operation. - */ - @Result - public int stop() { - return nativeStopDvr(); - } - - /** - * Flushed DVR data. - * - * <p>The data in DVR buffer is cleared. - * - * @return result status of the operation. - */ - @Result - public int flush() { - return nativeFlushDvr(); - } - - /** - * Closes the DVR instance to release resources. - */ - public void close() { - nativeClose(); - } - - /** - * Sets file descriptor to read/write data. - * - * @param fd the file descriptor to read/write data. - */ - public void setFileDescriptor(@NonNull ParcelFileDescriptor fd) { - nativeSetFileDescriptor(fd.getFd()); - } - - @Type - int getType() { - return mType; - } -} diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java index eb3157434a95..7c15bb74a94b 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java +++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java @@ -21,6 +21,9 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.hardware.tv.tuner.V1_0.Constants; +import android.media.tv.tuner.TunerConstants.Result; +import android.media.tv.tuner.filter.Filter; +import android.os.ParcelFileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -33,7 +36,7 @@ import java.lang.annotation.RetentionPolicy; * @hide */ @SystemApi -public class DvrPlayback extends Dvr { +public class DvrPlayback implements AutoCloseable { /** @hide */ @@ -66,17 +69,110 @@ public class DvrPlayback extends Dvr { */ public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL; + long mNativeContext; - + private native int nativeAttachFilter(Filter filter); + private native int nativeDetachFilter(Filter filter); + private native int nativeConfigureDvr(DvrSettings settings); + private native int nativeStartDvr(); + private native int nativeStopDvr(); + private native int nativeFlushDvr(); + private native int nativeClose(); + private native void nativeSetFileDescriptor(int fd); private native long nativeRead(long size); private native long nativeRead(byte[] bytes, long offset, long size); private DvrPlayback() { - super(Dvr.TYPE_PLAYBACK); } /** + * Attaches a filter to DVR interface for recording. + * + * @param filter the filter to be attached. + * @return result status of the operation. + */ + @Result + public int attachFilter(@NonNull Filter filter) { + return nativeAttachFilter(filter); + } + + /** + * Detaches a filter from DVR interface. + * + * @param filter the filter to be detached. + * @return result status of the operation. + */ + @Result + public int detachFilter(@NonNull Filter filter) { + return nativeDetachFilter(filter); + } + + /** + * Configures the DVR. + * + * @param settings the settings of the DVR interface. + * @return result status of the operation. + */ + @Result + public int configure(@NonNull DvrSettings settings) { + return nativeConfigureDvr(settings); + } + + /** + * Starts DVR. + * + * <p>Starts consuming playback data or producing data for recording. + * + * @return result status of the operation. + */ + @Result + public int start() { + return nativeStartDvr(); + } + + /** + * Stops DVR. + * + * <p>Stops consuming playback data or producing data for recording. + * + * @return result status of the operation. + */ + @Result + public int stop() { + return nativeStopDvr(); + } + + /** + * Flushed DVR data. + * + * <p>The data in DVR buffer is cleared. + * + * @return result status of the operation. + */ + @Result + public int flush() { + return nativeFlushDvr(); + } + + /** + * Closes the DVR instance to release resources. + */ + @Override + public void close() { + nativeClose(); + } + + /** + * Sets file descriptor to read/write data. + * + * @param fd the file descriptor to read/write data. + */ + public void setFileDescriptor(@NonNull ParcelFileDescriptor fd) { + nativeSetFileDescriptor(fd.getFd()); + } + + /** * Reads data from the file for DVR playback. * * @param size the maximum number of bytes to read. diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java index 3128ca5da641..52ef5e63389f 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java +++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java @@ -19,6 +19,9 @@ package android.media.tv.tuner.dvr; import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.media.tv.tuner.TunerConstants.Result; +import android.media.tv.tuner.filter.Filter; +import android.os.ParcelFileDescriptor; /** * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer. @@ -26,12 +29,108 @@ import android.annotation.SystemApi; * @hide */ @SystemApi -public class DvrRecorder extends Dvr { +public class DvrRecorder implements AutoCloseable { + long mNativeContext; + + private native int nativeAttachFilter(Filter filter); + private native int nativeDetachFilter(Filter filter); + private native int nativeConfigureDvr(DvrSettings settings); + private native int nativeStartDvr(); + private native int nativeStopDvr(); + private native int nativeFlushDvr(); + private native int nativeClose(); + private native void nativeSetFileDescriptor(int fd); private native long nativeWrite(long size); private native long nativeWrite(byte[] bytes, long offset, long size); private DvrRecorder() { - super(Dvr.TYPE_RECORD); + } + + + /** + * Attaches a filter to DVR interface for recording. + * + * @param filter the filter to be attached. + * @return result status of the operation. + */ + @Result + public int attachFilter(@NonNull Filter filter) { + return nativeAttachFilter(filter); + } + + /** + * Detaches a filter from DVR interface. + * + * @param filter the filter to be detached. + * @return result status of the operation. + */ + @Result + public int detachFilter(@NonNull Filter filter) { + return nativeDetachFilter(filter); + } + + /** + * Configures the DVR. + * + * @param settings the settings of the DVR interface. + * @return result status of the operation. + */ + @Result + public int configure(@NonNull DvrSettings settings) { + return nativeConfigureDvr(settings); + } + + /** + * Starts DVR. + * + * <p>Starts consuming playback data or producing data for recording. + * + * @return result status of the operation. + */ + @Result + public int start() { + return nativeStartDvr(); + } + + /** + * Stops DVR. + * + * <p>Stops consuming playback data or producing data for recording. + * + * @return result status of the operation. + */ + @Result + public int stop() { + return nativeStopDvr(); + } + + /** + * Flushed DVR data. + * + * <p>The data in DVR buffer is cleared. + * + * @return result status of the operation. + */ + @Result + public int flush() { + return nativeFlushDvr(); + } + + /** + * Closes the DVR instance to release resources. + */ + @Override + public void close() { + nativeClose(); + } + + /** + * Sets file descriptor to read/write data. + * + * @param fd the file descriptor to read/write data. + */ + public void setFileDescriptor(@NonNull ParcelFileDescriptor fd) { + nativeSetFileDescriptor(fd.getFd()); } /** diff --git a/media/java/android/media/tv/tuner/dvr/DvrSettings.java b/media/java/android/media/tv/tuner/dvr/DvrSettings.java index f9dc6821039a..362b108e41fd 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrSettings.java +++ b/media/java/android/media/tv/tuner/dvr/DvrSettings.java @@ -30,7 +30,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * DVR settings used to configure {@link Dvr}. + * DVR settings used to configure {@link DvrPlayback} and {@link DvrRecorder}. * * @hide */ diff --git a/media/java/android/media/voice/KeyphraseModelManager.java b/media/java/android/media/voice/KeyphraseModelManager.java index 3fa38e0a5854..8ec8967a353e 100644 --- a/media/java/android/media/voice/KeyphraseModelManager.java +++ b/media/java/android/media/voice/KeyphraseModelManager.java @@ -37,7 +37,8 @@ import java.util.Objects; * manage voice based sound trigger models. * Callers of this class are expected to have whitelist manifest permission MANAGE_VOICE_KEYPHRASES. * Callers of this class are expected to be the designated voice interaction service via - * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}. + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE} or a bundled voice model enrollment application + * detected by {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. * @hide */ @SystemApi @@ -65,6 +66,10 @@ public final class KeyphraseModelManager { * {@link #updateKeyphraseSoundModel}. * If the active voice interaction service changes from the current user, all requests will be * rejected, and any registered models will be unregistered. + * Caller must either be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model + * enrollment application detected by + * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. * * @param keyphraseId The unique identifier for the keyphrase. * @param locale The locale language tag supported by the desired model. @@ -93,6 +98,10 @@ public final class KeyphraseModelManager { * will be overwritten with the new model. * If the active voice interaction service changes from the current user, all requests will be * rejected, and any registered models will be unregistered. + * Caller must either be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model + * enrollment application detected by + * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. * * @param model Keyphrase sound model to be updated. * @throws ServiceSpecificException Thrown with error code if failed to update the keyphrase @@ -120,6 +129,10 @@ public final class KeyphraseModelManager { * {@link #updateKeyphraseSoundModel}. * If the active voice interaction service changes from the current user, all requests will be * rejected, and any registered models will be unregistered. + * Caller must either be the active voice interaction service via + * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model + * enrollment application detected by + * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. * * @param keyphraseId The unique identifier for the keyphrase. * @param locale The locale language tag supported by the desired model. diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 893e51654b68..737c95d73e6c 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -242,6 +242,13 @@ void JMediaCodec::release() { }); } +void JMediaCodec::releaseAsync() { + if (mCodec != NULL) { + mCodec->releaseAsync(); + } + mInitStatus = NO_INIT; +} + JMediaCodec::~JMediaCodec() { if (mLooper != NULL) { /* MediaCodec and looper should have been released explicitly already @@ -1124,7 +1131,10 @@ static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { } static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { - setMediaCodec(env, thiz, NULL); + sp<JMediaCodec> codec = getMediaCodec(env, thiz); + if (codec != NULL) { + codec->releaseAsync(); + } } static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) { @@ -2797,7 +2807,7 @@ static void android_media_MediaCodec_native_setup( static void android_media_MediaCodec_native_finalize( JNIEnv *env, jobject thiz) { - android_media_MediaCodec_release(env, thiz); + setMediaCodec(env, thiz, NULL); } // MediaCodec.LinearBlock diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index 8899fee7a73d..400ce1bc98e7 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -61,6 +61,7 @@ struct JMediaCodec : public AHandler { void registerSelf(); void release(); + void releaseAsync(); status_t enableOnFrameRenderedListener(jboolean enable); diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 5c39f296501c..e68ccfaa0812 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -119,7 +119,6 @@ using ::android::hardware::tv::tuner::V1_0::FrontendType; using ::android::hardware::tv::tuner::V1_0::ITuner; using ::android::hardware::tv::tuner::V1_0::PlaybackSettings; using ::android::hardware::tv::tuner::V1_0::RecordSettings; -using ::android::hardware::tv::tuner::V1_0::Result; struct fields_t { jfieldID tunerContext; @@ -845,22 +844,85 @@ int JTuner::setLna(bool enable) { return (int)result; } -bool JTuner::openDemux() { +Result JTuner::openDemux() { if (mTuner == nullptr) { - return false; + return Result::NOT_INITIALIZED; } if (mDemux != nullptr) { - return true; + return Result::SUCCESS; } - mTuner->openDemux([&](Result, uint32_t demuxId, const sp<IDemux>& demux) { + Result res; + mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) { mDemux = demux; mDemuxId = demuxId; + res = r; ALOGD("open demux, id = %d", demuxId); }); - if (mDemux == nullptr) { - return false; + return res; +} + +jobject JTuner::getAvSyncHwId(sp<Filter> filter) { + if (mDemux == NULL) { + return NULL; } - return true; + + uint32_t avSyncHwId; + Result res; + sp<IFilter> iFilterSp = filter->getIFilter(); + mDemux->getAvSyncHwId(iFilterSp, + [&](Result r, uint32_t id) { + res = r; + avSyncHwId = id; + }); + if (res == Result::SUCCESS) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jclass integerClazz = env->FindClass("java/lang/Integer"); + jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V"); + return env->NewObject(integerClazz, intInit, avSyncHwId); + } + return NULL; +} + +jobject JTuner::getAvSyncTime(jint id) { + if (mDemux == NULL) { + return NULL; + } + uint64_t time; + Result res; + mDemux->getAvSyncTime(static_cast<uint32_t>(id), + [&](Result r, uint64_t ts) { + res = r; + time = ts; + }); + if (res == Result::SUCCESS) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jclass longClazz = env->FindClass("java/lang/Long"); + jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V"); + return env->NewObject(longClazz, longInit, static_cast<jlong>(time)); + } + return NULL; +} + +int JTuner::connectCiCam(jint id) { + if (mDemux == NULL) { + Result r = openDemux(); + if (r != Result::SUCCESS) { + return (int) r; + } + } + Result r = mDemux->connectCiCam(static_cast<uint32_t>(id)); + return (int) r; +} + +int JTuner::disconnectCiCam() { + if (mDemux == NULL) { + Result r = openDemux(); + if (r != Result::SUCCESS) { + return (int) r; + } + } + Result r = mDemux->disconnectCiCam(); + return (int) r; } jobject JTuner::openDescrambler() { @@ -892,7 +954,7 @@ jobject JTuner::openDescrambler() { jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { if (mDemux == NULL) { - if (!openDemux()) { + if (openDemux() != Result::SUCCESS) { return NULL; } } @@ -917,7 +979,6 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { env->NewObject( env->FindClass("android/media/tv/tuner/filter/Filter"), gFields.filterInitID, - mObject, (jint) fId); sp<Filter> filterSp = new Filter(iFilterSp, filterObj); @@ -931,7 +992,7 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { jobject JTuner::openTimeFilter() { if (mDemux == NULL) { - if (!openDemux()) { + if (openDemux() != Result::SUCCESS) { return NULL; } } @@ -962,7 +1023,7 @@ jobject JTuner::openTimeFilter() { jobject JTuner::openDvr(DvrType type, int bufferSize) { ALOGD("JTuner::openDvr"); if (mDemux == NULL) { - if (!openDemux()) { + if (openDemux() != Result::SUCCESS) { return NULL; } } @@ -1608,20 +1669,30 @@ static jobject android_media_tv_Tuner_get_frontend_status(JNIEnv, jobject, jintA return NULL; } -static int android_media_tv_Tuner_gat_av_sync_hw_id(JNIEnv*, jobject, jobject) { - return 0; +static jobject android_media_tv_Tuner_get_av_sync_hw_id( + JNIEnv *env, jobject thiz, jobject filter) { + sp<Filter> filterSp = getFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed to get sync ID. Filter not found"); + return NULL; + } + sp<JTuner> tuner = getTuner(env, thiz); + return tuner->getAvSyncHwId(filterSp); } -static jlong android_media_tv_Tuner_gat_av_sync_time(JNIEnv*, jobject, jint) { - return 0; +static jobject android_media_tv_Tuner_get_av_sync_time(JNIEnv *env, jobject thiz, jint id) { + sp<JTuner> tuner = getTuner(env, thiz); + return tuner->getAvSyncTime(id); } -static int android_media_tv_Tuner_connect_cicam(JNIEnv*, jobject, jint) { - return 0; +static int android_media_tv_Tuner_connect_cicam(JNIEnv *env, jobject thiz, jint id) { + sp<JTuner> tuner = getTuner(env, thiz); + return tuner->connectCiCam(id); } -static int android_media_tv_Tuner_disconnect_cicam(JNIEnv*, jobject) { - return 0; +static int android_media_tv_Tuner_disconnect_cicam(JNIEnv *env, jobject thiz) { + sp<JTuner> tuner = getTuner(env, thiz); + return tuner->disconnectCiCam(); } static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thiz, jint id) { @@ -2500,9 +2571,10 @@ static const JNINativeMethod gTunerMethods[] = { { "nativeSetLna", "(Z)I", (void *)android_media_tv_Tuner_set_lna }, { "nativeGetFrontendStatus", "([I)Landroid/media/tv/tuner/frontend/FrontendStatus;", (void *)android_media_tv_Tuner_get_frontend_status }, - { "nativeGetAvSyncHwId", "(Landroid/media/tv/tuner/filter/Filter;)I", - (void *)android_media_tv_Tuner_gat_av_sync_hw_id }, - { "nativeGetAvSyncTime", "(I)J", (void *)android_media_tv_Tuner_gat_av_sync_time }, + { "nativeGetAvSyncHwId", "(Landroid/media/tv/tuner/filter/Filter;)Ljava/lang/Integer;", + (void *)android_media_tv_Tuner_get_av_sync_hw_id }, + { "nativeGetAvSyncTime", "(I)Ljava/lang/Long;", + (void *)android_media_tv_Tuner_get_av_sync_time }, { "nativeConnectCiCam", "(I)I", (void *)android_media_tv_Tuner_connect_cicam }, { "nativeDisconnectCiCam", "()I", (void *)android_media_tv_Tuner_disconnect_cicam }, { "nativeGetFrontendInfo", "(I)Landroid/media/tv/tuner/frontend/FrontendInfo;", diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 32d489979d2b..b786fc4e76b7 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -60,6 +60,7 @@ using ::android::hardware::tv::tuner::V1_0::LnbEventType; using ::android::hardware::tv::tuner::V1_0::LnbId; using ::android::hardware::tv::tuner::V1_0::PlaybackStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; +using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; @@ -141,6 +142,10 @@ struct TimeFilter : public RefBase { struct JTuner : public RefBase { JTuner(JNIEnv *env, jobject thiz); sp<ITuner> getTunerService(); + jobject getAvSyncHwId(sp<Filter> filter); + jobject getAvSyncTime(jint id); + int connectCiCam(jint id); + int disconnectCiCam(); jobject getFrontendIds(); jobject openFrontendById(int id); jobject getFrontendInfo(int id); @@ -158,7 +163,7 @@ struct JTuner : public RefBase { jobject openDvr(DvrType type, int bufferSize); protected: - bool openDemux(); + Result openDemux(); virtual ~JTuner(); private: diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java index bcff6a1df918..230b9e4bfaad 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java @@ -123,7 +123,7 @@ public class MediaRouter2ManagerTest { @Test public void testOnRoutesRemovedAndAdded() throws Exception { - RouteCallback routeCallback = new RouteCallback(); + RouteCallback routeCallback = new RouteCallback() {}; mRouteCallbacks.add(routeCallback); mRouter2.registerRouteCallback(mExecutor, routeCallback, new RouteDiscoveryPreference.Builder(FEATURES_ALL, true).build()); @@ -201,7 +201,7 @@ public class MediaRouter2ManagerTest { addManagerCallback(new MediaRouter2Manager.Callback()); //TODO: remove this when it's not necessary. - addRouterCallback(new MediaRouter2.RouteCallback()); + addRouterCallback(new MediaRouter2.RouteCallback() {}); addTransferCallback(new MediaRouter2.TransferCallback() { @Override public void onTransferred(MediaRouter2.RoutingController oldController, @@ -228,7 +228,7 @@ public class MediaRouter2ManagerTest { CountDownLatch latch = new CountDownLatch(1); Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); - addRouterCallback(new RouteCallback()); + addRouterCallback(new RouteCallback() {}); addManagerCallback(new MediaRouter2Manager.Callback() { @Override public void onSessionCreated(MediaRouter2Manager.RoutingController controller) { @@ -248,10 +248,9 @@ public class MediaRouter2ManagerTest { assertEquals(2, sessions.size()); - MediaRouter2Manager.RoutingController routingController = - mManager.getControllerForSession(sessions.get(1)); + RoutingSessionInfo sessionInfo = sessions.get(1); awaitOnRouteChangedManager( - () -> routingController.release(), + () -> mManager.releaseSession(sessionInfo), ROUTE_ID1, route -> TextUtils.equals(route.getClientPackageName(), null)); assertEquals(1, mManager.getRoutingSessions(mPackageName).size()); @@ -263,7 +262,7 @@ public class MediaRouter2ManagerTest { @Test public void testSelectAndTransferAndRelease() throws Exception { Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); - addRouterCallback(new RouteCallback()); + addRouterCallback(new RouteCallback() {}); CountDownLatch onSessionCreatedLatch = new CountDownLatch(1); @@ -283,8 +282,7 @@ public class MediaRouter2ManagerTest { List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName); assertEquals(2, sessions.size()); - MediaRouter2Manager.RoutingController routingController = - mManager.getControllerForSession(sessions.get(1)); + RoutingSessionInfo sessionInfo = sessions.get(1); awaitOnRouteChangedManager( () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID5_TO_TRANSFER_TO)), @@ -292,7 +290,7 @@ public class MediaRouter2ManagerTest { route -> TextUtils.equals(route.getClientPackageName(), mPackageName)); awaitOnRouteChangedManager( - () -> routingController.release(), + () -> mManager.releaseSession(sessionInfo), ROUTE_ID5_TO_TRANSFER_TO, route -> TextUtils.equals(route.getClientPackageName(), null)); } @@ -346,7 +344,7 @@ public class MediaRouter2ManagerTest { @Test public void testSetSessionVolume() throws Exception { Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); - addRouterCallback(new RouteCallback()); + addRouterCallback(new RouteCallback() {}); CountDownLatch onSessionCreatedLatch = new CountDownLatch(1); CountDownLatch volumeChangedLatch = new CountDownLatch(2); @@ -471,7 +469,7 @@ public class MediaRouter2ManagerTest { CountDownLatch featuresLatch = new CountDownLatch(1); // A dummy callback is required to send route feature info. - RouteCallback routeCallback = new RouteCallback(); + RouteCallback routeCallback = new RouteCallback() {}; MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() { @Override public void onRoutesAdded(List<MediaRoute2Info> routes) { @@ -573,7 +571,7 @@ public class MediaRouter2ManagerTest { addManagerCallback(new MediaRouter2Manager.Callback()); for (RoutingSessionInfo session : mManager.getActiveSessions()) { - mManager.getControllerForSession(session).release(); + mManager.releaseSession(session); } } } diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java index 3a5201517af2..b2c16b3aef1b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java @@ -16,6 +16,12 @@ package com.android.systemui.navigationbar.car; +import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; +import static android.view.InsetsState.containsType; + +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; + import android.content.Context; import android.graphics.PixelFormat; import android.inputmethodservice.InputMethodService; @@ -37,9 +43,12 @@ import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarDeviceProvisionedListener; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.SuperStatusBarViewFactory; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.BarTransitions; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -57,6 +66,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private final WindowManager mWindowManager; private final CarDeviceProvisionedController mCarDeviceProvisionedController; private final CommandQueue mCommandQueue; + private final AutoHideController mAutoHideController; private final ButtonSelectionStateListener mButtonSelectionStateListener; private final Handler mMainHandler; private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy; @@ -64,6 +74,8 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; private final ButtonSelectionStateController mButtonSelectionStateController; + private final int mDisplayId; + private IStatusBarService mBarService; private ActivityManagerWrapper mActivityManagerWrapper; @@ -86,12 +98,16 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private boolean mDeviceIsSetUpForUser = true; private boolean mIsUserSetupInProgress = false; + private @BarTransitions.TransitionMode int mNavigationBarMode; + private boolean mTransientShown; + @Inject public CarNavigationBar(Context context, CarNavigationBarController carNavigationBarController, WindowManager windowManager, DeviceProvisionedController deviceProvisionedController, CommandQueue commandQueue, + AutoHideController autoHideController, ButtonSelectionStateListener buttonSelectionStateListener, @Main Handler mainHandler, Lazy<KeyguardStateController> keyguardStateControllerLazy, @@ -104,12 +120,15 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks mCarDeviceProvisionedController = (CarDeviceProvisionedController) deviceProvisionedController; mCommandQueue = commandQueue; + mAutoHideController = autoHideController; mButtonSelectionStateListener = buttonSelectionStateListener; mMainHandler = mainHandler; mKeyguardStateControllerLazy = keyguardStateControllerLazy; mNavigationBarControllerLazy = navigationBarControllerLazy; mSuperStatusBarViewFactory = superStatusBarViewFactory; mButtonSelectionStateController = buttonSelectionStateController; + + mDisplayId = mWindowManager.getDefaultDisplay().getDisplayId(); } @Override @@ -133,6 +152,23 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks ex.rethrowFromSystemServer(); } + mAutoHideController.addAutoHideUiElement(new AutoHideUiElement() { + @Override + public void synchronizeState() { + // No op. + } + + @Override + public boolean isVisible() { + return mTransientShown; + } + + @Override + public void hide() { + clearTransient(); + } + }); + mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup(); mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress(); mCarDeviceProvisionedController.addCallback( @@ -341,10 +377,57 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks } @Override + public void showTransient(int displayId, int[] types) { + if (displayId != mDisplayId) { + return; + } + if (!containsType(types, ITYPE_NAVIGATION_BAR)) { + return; + } + + if (!mTransientShown) { + mTransientShown = true; + handleTransientChanged(); + } + } + + @Override + public void abortTransient(int displayId, int[] types) { + if (displayId != mDisplayId) { + return; + } + if (!containsType(types, ITYPE_NAVIGATION_BAR)) { + return; + } + clearTransient(); + } + + private void clearTransient() { + if (mTransientShown) { + mTransientShown = false; + handleTransientChanged(); + } + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print(" mTaskStackListener="); pw.println(mButtonSelectionStateListener); pw.print(" mBottomNavigationBarView="); pw.println(mBottomNavigationBarView); } + + private void handleTransientChanged() { + updateBarMode(mTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT); + } + + // Returns true if the bar mode is changed. + private boolean updateBarMode(int barMode) { + if (mNavigationBarMode != barMode) { + mNavigationBarMode = barMode; + mAutoHideController.touchAutoHide(); + return true; + } + return false; + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index a4eada4ebe0b..f39f9124efbb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -122,6 +122,7 @@ import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; +import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -324,6 +325,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, + PhoneStatusBarPolicy phoneStatusBarPolicy, DismissCallbackRegistry dismissCallbackRegistry, StatusBarTouchableRegionManager statusBarTouchableRegionManager, /* Car Settings injected components. */ @@ -407,6 +409,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt keyguardDismissUtil, extensionController, userInfoControllerImpl, + phoneStatusBarPolicy, dismissCallbackRegistry, statusBarTouchableRegionManager); mUserSwitcherController = userSwitcherController; diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java index 729496580bf6..843e7c55852a 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -82,6 +82,7 @@ import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; +import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -197,6 +198,7 @@ public class CarStatusBarModule { KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, + PhoneStatusBarPolicy phoneStatusBarPolicy, DismissCallbackRegistry dismissCallbackRegistry, StatusBarTouchableRegionManager statusBarTouchableRegionManager, CarServiceProvider carServiceProvider, @@ -278,6 +280,7 @@ public class CarStatusBarModule { keyguardDismissUtil, extensionController, userInfoControllerImpl, + phoneStatusBarPolicy, dismissCallbackRegistry, statusBarTouchableRegionManager, carServiceProvider, diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml index a9c668599a2a..ea9b52cbf3d5 100644 --- a/packages/CompanionDeviceManager/AndroidManifest.xml +++ b/packages/CompanionDeviceManager/AndroidManifest.xml @@ -30,11 +30,13 @@ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <uses-permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"/> + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> <application android:allowClearUserData="true" android:label="@string/app_label" android:allowBackup="false" + android:forceQueryable="true" android:supportsRtl="true"> <service diff --git a/packages/Incremental/NativeAdbDataLoader/Android.bp b/packages/Incremental/NativeAdbDataLoader/Android.bp deleted file mode 100644 index 5d7b5b6c229d..000000000000 --- a/packages/Incremental/NativeAdbDataLoader/Android.bp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019, The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -android_app { - name: "NativeAdbDataLoaderService", - srcs: ["src/**/*.java"], - jni_libs: [ "libnativeadbdataloaderservice_jni"], - privileged: true, - certificate: "platform", - platform_apis: true, -} diff --git a/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml b/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml deleted file mode 100644 index c4d8f35cec71..000000000000 --- a/packages/Incremental/NativeAdbDataLoader/AndroidManifest.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** Copyright 2019, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - coreApp="true" - package="com.android.incremental.nativeadb" - android:sharedUserId="android.uid.system"> - <uses-permission android:name="android.permission.INTERNET" /> - - <application android:label="@string/app_name" - android:directBootAware="true"> - - <service android:enabled="true" - android:name="com.android.incremental.nativeadb.NativeAdbDataLoaderService" - android:label="@string/app_name" - android:exported="false"> - <intent-filter> - <action android:name="android.intent.action.LOAD_DATA" /> - </intent-filter> - </service> - </application> - -</manifest> diff --git a/packages/Incremental/NativeAdbDataLoader/jni/Android.bp b/packages/Incremental/NativeAdbDataLoader/jni/Android.bp deleted file mode 100644 index 0fcfd28cf28c..000000000000 --- a/packages/Incremental/NativeAdbDataLoader/jni/Android.bp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019, The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_library_shared { - name: "libnativeadbdataloaderservice_jni", - cpp_std: "c++2a", - cflags: [ - "-Wall", - "-Werror", - "-Wunused", - "-Wunreachable-code", - "-Wno-unused-parameter", - ], - - srcs: ["com_android_incremental_nativeadb_DataLoaderService.cpp"], - - shared_libs: [ - "libbase", - "libcutils", - "libincfs", - "libdataloader", - "liblog", - "libnativehelper", - "libutils", - ], -} diff --git a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp deleted file mode 100644 index c0cd5272e7e6..000000000000 --- a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_ADB -#define LOG_TAG "NativeAdbDataLoaderService" - -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/properties.h> -#include <android-base/stringprintf.h> -#include <android-base/thread_annotations.h> -#include <android-base/unique_fd.h> -#include <cutils/trace.h> -#include <fcntl.h> -#include <sys/eventfd.h> -#include <sys/poll.h> -#include <sys/stat.h> -#include <unistd.h> -#include <utils/Log.h> - -#include <charconv> -#include <span> -#include <string> -#include <thread> -#include <type_traits> -#include <unordered_map> -#include <unordered_set> - -#include "dataloader.h" - -#ifndef _WIN32 -#include <endian.h> -#include <sys/stat.h> -#include <unistd.h> -#else -#define be32toh(x) _byteswap_ulong(x) -#define be16toh(x) _byteswap_ushort(x) -#endif - -namespace { - -using android::base::unique_fd; - -using namespace std::literals; - -using BlockSize = int16_t; -using FileId = int16_t; -using BlockIdx = int32_t; -using NumBlocks = int32_t; -using CompressionType = int16_t; -using RequestType = int16_t; - -static constexpr int COMMAND_SIZE = 2 + 2 + 4; // bytes -static constexpr int HEADER_SIZE = 2 + 2 + 4 + 2; // bytes -static constexpr std::string_view OKAY = "OKAY"sv; - -static constexpr auto PollTimeoutMs = 5000; - -static constexpr auto ReadLogBufferSize = 128 * 1024 * 1024; -static constexpr auto ReadLogMaxEntrySize = 128; - -struct BlockHeader { - FileId fileId = -1; - CompressionType compressionType = -1; - BlockIdx blockIdx = -1; - BlockSize blockSize = -1; -} __attribute__((packed)); - -static_assert(sizeof(BlockHeader) == HEADER_SIZE); - -static constexpr RequestType EXIT = 0; -static constexpr RequestType BLOCK_MISSING = 1; -static constexpr RequestType PREFETCH = 2; - -struct RequestCommand { - RequestType requestType; - FileId fileId; - BlockIdx blockIdx; -} __attribute__((packed)); - -static_assert(COMMAND_SIZE == sizeof(RequestCommand)); - -static bool sendRequest(int fd, RequestType requestType, FileId fileId = -1, - BlockIdx blockIdx = -1) { - const RequestCommand command{.requestType = static_cast<int16_t>(be16toh(requestType)), - .fileId = static_cast<int16_t>(be16toh(fileId)), - .blockIdx = static_cast<int32_t>(be32toh(blockIdx))}; - return android::base::WriteFully(fd, &command, sizeof(command)); -} - -static int waitForDataOrSignal(int fd, int event_fd) { - struct pollfd pfds[2] = {{fd, POLLIN, 0}, {event_fd, POLLIN, 0}}; - // Wait indefinitely until either data is ready or stop signal is received - int res = poll(pfds, 2, PollTimeoutMs); - if (res <= 0) { - return res; - } - // First check if there is a stop signal - if (pfds[1].revents == POLLIN) { - return event_fd; - } - // Otherwise check if incoming data is ready - if (pfds[0].revents == POLLIN) { - return fd; - } - return -1; -} - -static bool readChunk(int fd, std::vector<uint8_t>& data) { - int32_t size; - if (!android::base::ReadFully(fd, &size, sizeof(size))) { - return false; - } - size = int32_t(be32toh(size)); - if (size <= 0) { - return false; - } - data.resize(size); - return android::base::ReadFully(fd, data.data(), data.size()); -} - -static BlockHeader readHeader(std::span<uint8_t>& data) { - BlockHeader header; - if (data.size() < sizeof(header)) { - return header; - } - - header.fileId = static_cast<FileId>(be16toh(*reinterpret_cast<uint16_t*>(&data[0]))); - header.compressionType = - static_cast<CompressionType>(be16toh(*reinterpret_cast<uint16_t*>(&data[2]))); - header.blockIdx = static_cast<BlockIdx>(be32toh(*reinterpret_cast<uint32_t*>(&data[4]))); - header.blockSize = static_cast<BlockSize>(be16toh(*reinterpret_cast<uint16_t*>(&data[8]))); - data = data.subspan(sizeof(header)); - - return header; -} - -static std::string extractPackageName(const std::string& staticArgs) { - static constexpr auto kPrefix = "package="sv; - static constexpr auto kSuffix = "&"sv; - - const auto startPos = staticArgs.find(kPrefix); - if (startPos == staticArgs.npos || startPos + kPrefix.size() >= staticArgs.size()) { - return {}; - } - const auto endPos = staticArgs.find(kSuffix, startPos + kPrefix.size()); - return staticArgs.substr(startPos + kPrefix.size(), - endPos == staticArgs.npos ? staticArgs.npos - : (endPos - (startPos + kPrefix.size()))); -} - -class AdbDataLoader : public android::dataloader::DataLoader { -private: - // Lifecycle. - bool onCreate(const android::dataloader::DataLoaderParams& params, - android::dataloader::FilesystemConnectorPtr ifs, - android::dataloader::StatusListenerPtr statusListener, - android::dataloader::ServiceConnectorPtr, - android::dataloader::ServiceParamsPtr) final { - CHECK(ifs) << "ifs can't be null"; - CHECK(statusListener) << "statusListener can't be null"; - ALOGE("[AdbDataLoader] onCreate: %d/%s/%s/%s/%d", params.type(), - params.packageName().c_str(), params.className().c_str(), params.arguments().c_str(), - (int)params.dynamicArgs().size()); - - if (params.dynamicArgs().empty()) { - ALOGE("[AdbDataLoader] Invalid DataLoaderParams. Need in/out FDs."); - return false; - } - for (auto const& namedFd : params.dynamicArgs()) { - if (namedFd.name == "inFd") { - mInFd.reset(dup(namedFd.fd)); - } - if (namedFd.name == "outFd") { - mOutFd.reset(dup(namedFd.fd)); - } - } - if (mInFd < 0 || mOutFd < 0) { - ALOGE("[AdbDataLoader] Failed to dup FDs."); - return false; - } - - mEventFd.reset(eventfd(0, EFD_CLOEXEC)); - if (mEventFd < 0) { - ALOGE("[AdbDataLoader] Failed to create eventfd."); - return false; - } - - std::string logFile; - if (const auto packageName = extractPackageName(params.arguments()); !packageName.empty()) { - logFile = android::base::GetProperty("adb.readlog." + packageName, ""); - } - if (logFile.empty()) { - logFile = android::base::GetProperty("adb.readlog", ""); - } - if (!logFile.empty()) { - int flags = O_WRONLY | O_CREAT | O_CLOEXEC; - mReadLogFd.reset(TEMP_FAILURE_RETRY(open(logFile.c_str(), flags, 0666))); - } - - mIfs = ifs; - mStatusListener = statusListener; - ALOGE("[AdbDataLoader] Successfully created data loader."); - return true; - } - - bool onStart() final { - char okay_buf[OKAY.size()]; - if (!android::base::ReadFully(mInFd, okay_buf, OKAY.size())) { - ALOGE("[AdbDataLoader] Failed to receive OKAY. Abort."); - return false; - } - if (std::string_view(okay_buf, OKAY.size()) != OKAY) { - ALOGE("[AdbDataLoader] Received '%.*s', expecting '%.*s'", (int)OKAY.size(), okay_buf, - (int)OKAY.size(), OKAY.data()); - return false; - } - - mReceiverThread = std::thread([this]() { receiver(); }); - ALOGI("[AdbDataLoader] started loading..."); - return true; - } - - void onStop() final { - mStopReceiving = true; - eventfd_write(mEventFd, 1); - if (mReceiverThread.joinable()) { - mReceiverThread.join(); - } - } - - void onDestroy() final { - ALOGE("[AdbDataLoader] Sending EXIT to server."); - sendRequest(mOutFd, EXIT); - // Make sure the receiver thread was stopped - CHECK(!mReceiverThread.joinable()); - - mInFd.reset(); - mOutFd.reset(); - - mNodeToMetaMap.clear(); - mIdToNodeMap.clear(); - - flushReadLog(); - mReadLogFd.reset(); - } - - // Installation callback - bool onPrepareImage(const android::dataloader::DataLoaderInstallationFiles& addedFiles) final { - return true; - } - - // IFS callbacks. - void onPendingReads(const android::dataloader::PendingReads& pendingReads) final { - std::lock_guard lock{mMapsMutex}; - CHECK(mIfs); - for (auto&& pendingRead : pendingReads) { - const android::dataloader::FileId id = pendingRead.id; - const auto blockIdx = static_cast<BlockIdx>(pendingRead.block); - /* - ALOGI("[AdbDataLoader] Missing: %d", (int) blockIdx); - */ - auto fileIdOr = getFileId(id); - if (!fileIdOr) { - ALOGE("[AdbDataLoader] Failed to handle event for fileid=%s. " - "Ignore.", - android::incfs::toString(id).c_str()); - continue; - } - const FileId fileId = *fileIdOr; - if (mRequestedFiles.insert(fileId).second) { - if (!sendRequest(mOutFd, PREFETCH, fileId, blockIdx)) { - ALOGE("[AdbDataLoader] Failed to request prefetch for " - "fileid=%s. Ignore.", - android::incfs::toString(id).c_str()); - mRequestedFiles.erase(fileId); - mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION); - } - } - sendRequest(mOutFd, BLOCK_MISSING, fileId, blockIdx); - } - } - - struct TracedRead { - uint64_t timestampUs; - android::dataloader::FileId fileId; - uint32_t firstBlockIdx; - uint32_t count; - }; - void onPageReads(const android::dataloader::PageReads& pageReads) final { - auto trace = atrace_is_tag_enabled(ATRACE_TAG); - auto log = mReadLogFd != -1; - if (CC_LIKELY(!(trace || log))) { - return; - } - - TracedRead last = {}; - std::lock_guard lock{mMapsMutex}; - for (auto&& read : pageReads) { - if (read.id != last.fileId || read.block != last.firstBlockIdx + last.count) { - traceOrLogRead(last, trace, log); - last = {read.bootClockTsUs, read.id, (uint32_t)read.block, 1}; - } else { - ++last.count; - } - } - traceOrLogRead(last, trace, log); - } - void onFileCreated(android::dataloader::FileId fileid, - const android::dataloader::RawMetadata& metadata) {} - -private: - void receiver() { - std::vector<uint8_t> data; - std::vector<IncFsDataBlock> instructions; - std::unordered_map<android::dataloader::FileId, unique_fd> writeFds; - while (!mStopReceiving) { - const int res = waitForDataOrSignal(mInFd, mEventFd); - if (res == 0) { - flushReadLog(); - continue; - } - if (res < 0) { - ALOGE("[AdbDataLoader] failed to poll. Abort."); - mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION); - break; - } - if (res == mEventFd) { - ALOGE("[AdbDataLoader] received stop signal. Exit."); - break; - } - if (!readChunk(mInFd, data)) { - ALOGE("[AdbDataLoader] failed to read a message. Abort."); - mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION); - break; - } - auto remainingData = std::span(data); - while (!remainingData.empty()) { - auto header = readHeader(remainingData); - if (header.fileId == -1 && header.compressionType == 0 && header.blockIdx == 0 && - header.blockSize == 0) { - ALOGI("[AdbDataLoader] stop signal received. Sending " - "exit command (remaining bytes: %d).", - int(remainingData.size())); - - sendRequest(mOutFd, EXIT); - mStopReceiving = true; - break; - } - if (header.fileId < 0 || header.blockSize <= 0 || header.compressionType < 0 || - header.blockIdx < 0) { - ALOGE("[AdbDataLoader] invalid header received. Abort."); - mStopReceiving = true; - break; - } - const android::dataloader::FileId id = mIdToNodeMap[header.fileId]; - if (!android::incfs::isValidFileId(id)) { - ALOGE("Unknown data destination for file ID %d. " - "Ignore.", - header.fileId); - continue; - } - - auto& writeFd = writeFds[id]; - if (writeFd < 0) { - writeFd = this->mIfs->openWrite(id); - if (writeFd < 0) { - ALOGE("Failed to open file %d for writing (%d). Aboring.", header.fileId, - -writeFd); - break; - } - } - - const auto inst = IncFsDataBlock{ - .fileFd = writeFd, - .pageIndex = static_cast<IncFsBlockIndex>(header.blockIdx), - .compression = static_cast<IncFsCompressionKind>(header.compressionType), - .kind = INCFS_BLOCK_KIND_DATA, - .dataSize = static_cast<uint16_t>(header.blockSize), - .data = (const char*)remainingData.data(), - }; - instructions.push_back(inst); - remainingData = remainingData.subspan(header.blockSize); - } - writeInstructions(instructions); - } - writeInstructions(instructions); - flushReadLog(); - } - - void writeInstructions(std::vector<IncFsDataBlock>& instructions) { - auto res = this->mIfs->writeBlocks(instructions); - if (res != instructions.size()) { - ALOGE("[AdbDataLoader] failed to write data to Incfs (res=%d when " - "expecting %d)", - res, int(instructions.size())); - } - instructions.clear(); - } - - struct MetaPair { - android::dataloader::RawMetadata meta; - FileId fileId; - }; - - MetaPair* updateMapsForFile(android::dataloader::FileId id) { - android::dataloader::RawMetadata meta = mIfs->getRawMetadata(id); - FileId fileId; - auto res = std::from_chars(meta.data(), meta.data() + meta.size(), fileId); - if (res.ec != std::errc{} || fileId < 0) { - ALOGE("[AdbDataLoader] Invalid metadata for fileid=%s (%s)", - android::incfs::toString(id).c_str(), meta.data()); - return nullptr; - } - mIdToNodeMap[fileId] = id; - auto& metaPair = mNodeToMetaMap[id]; - metaPair.meta = std::move(meta); - metaPair.fileId = fileId; - return &metaPair; - } - - android::dataloader::RawMetadata* getMeta(android::dataloader::FileId id) { - auto it = mNodeToMetaMap.find(id); - if (it != mNodeToMetaMap.end()) { - return &it->second.meta; - } - - auto metaPair = updateMapsForFile(id); - if (!metaPair) { - return nullptr; - } - - return &metaPair->meta; - } - - FileId* getFileId(android::dataloader::FileId id) { - auto it = mNodeToMetaMap.find(id); - if (it != mNodeToMetaMap.end()) { - return &it->second.fileId; - } - - auto* metaPair = updateMapsForFile(id); - if (!metaPair) { - return nullptr; - } - - return &metaPair->fileId; - } - - void traceOrLogRead(const TracedRead& read, bool trace, bool log) { - if (!read.count) { - return; - } - if (trace) { - auto* meta = getMeta(read.fileId); - auto str = android::base::StringPrintf("page_read: index=%lld count=%lld meta=%.*s", - static_cast<long long>(read.firstBlockIdx), - static_cast<long long>(read.count), - meta ? int(meta->size()) : 0, - meta ? meta->data() : ""); - ATRACE_BEGIN(str.c_str()); - ATRACE_END(); - } - if (log) { - mReadLog.reserve(ReadLogBufferSize); - - auto fileId = getFileId(read.fileId); - android::base::StringAppendF(&mReadLog, "%lld:%lld:%lld:%lld\n", - static_cast<long long>(read.timestampUs), - static_cast<long long>(fileId ? *fileId : -1), - static_cast<long long>(read.firstBlockIdx), - static_cast<long long>(read.count)); - - if (mReadLog.size() >= mReadLog.capacity() - ReadLogMaxEntrySize) { - flushReadLog(); - } - } - } - - void flushReadLog() { - if (mReadLog.empty() || mReadLogFd == -1) { - return; - } - - android::base::WriteStringToFd(mReadLog, mReadLogFd); - mReadLog.clear(); - } - -private: - android::dataloader::FilesystemConnectorPtr mIfs = nullptr; - android::dataloader::StatusListenerPtr mStatusListener = nullptr; - android::base::unique_fd mInFd; - android::base::unique_fd mOutFd; - android::base::unique_fd mEventFd; - android::base::unique_fd mReadLogFd; - std::string mReadLog; - std::thread mReceiverThread; - std::mutex mMapsMutex; - std::unordered_map<android::dataloader::FileId, MetaPair> mNodeToMetaMap GUARDED_BY(mMapsMutex); - std::unordered_map<FileId, android::dataloader::FileId> mIdToNodeMap GUARDED_BY(mMapsMutex); - /** Tracks which files have been requested */ - std::unordered_set<FileId> mRequestedFiles; - std::atomic<bool> mStopReceiving = false; -}; - -} // namespace - -int JNI_OnLoad(JavaVM* jvm, void* /* reserved */) { - android::dataloader::DataLoader::initialize( - [](auto, auto) { return std::make_unique<AdbDataLoader>(); }); - return JNI_VERSION_1_6; -} diff --git a/packages/Incremental/NativeAdbDataLoader/res/values/strings.xml b/packages/SettingsLib/SchedulesProvider/res/values/config.xml index 9921ae69a7f5..48f3e3ef4542 100644 --- a/packages/Incremental/NativeAdbDataLoader/res/values/strings.xml +++ b/packages/SettingsLib/SchedulesProvider/res/values/config.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 The Android Open Source Project +<!-- 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. @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Name of the Data Loader Service. [CHAR LIMIT=40] --> - <string name="app_name">Native Adb Data Loader Service</string> -</resources> +<resources> + <!-- Package name for the caller of the Schedules provider. --> + <string name="config_schedules_provider_caller_package" translatable="false">com.android.settings</string> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java index 7d2b8e2878d6..26bcd54930b6 100644 --- a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java +++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java @@ -24,9 +24,9 @@ import android.text.TextUtils; import androidx.annotation.NonNull; /** - * This is a schedule data item. It contains the schedule title text, the summary text which - * displays on the summary of the Settings preference and an {@link Intent}. Intent is able to - * launch the editing page of the schedule data when user clicks this item (preference). + * Schedule data item containing the schedule title text, the summary text which is displayed on the + * summary of the Settings preference and an {@link Intent} which Settings will launch when the + * user clicks on the preference. */ public class ScheduleInfo implements Parcelable { private static final String TAG = "ScheduleInfo"; @@ -40,7 +40,7 @@ public class ScheduleInfo implements Parcelable { mIntent = builder.mIntent; } - protected ScheduleInfo(Parcel in) { + private ScheduleInfo(Parcel in) { mTitle = in.readString(); mSummary = in.readString(); mIntent = in.readParcelable(Intent.class.getClassLoader()); @@ -48,8 +48,6 @@ public class ScheduleInfo implements Parcelable { /** * Returns the title text. - * - * @return The title. */ public String getTitle() { return mTitle; @@ -57,15 +55,14 @@ public class ScheduleInfo implements Parcelable { /** * Returns the summary text. - * - * @return The summary. */ public String getSummary() { return mSummary; } /** - * Returns an {@link Intent}. + * Returns an {@link Intent} which Settings will launch when the user clicks on a schedule + * preference. */ public Intent getIntent() { return mIntent; @@ -107,19 +104,15 @@ public class ScheduleInfo implements Parcelable { @NonNull @Override public String toString() { - return "title : " + mTitle + " summary : " + mSummary + (mIntent == null - ? " and intent is null." : "."); + return "title: " + mTitle + ", summary: " + mSummary + ", intent: " + mIntent; } /** * A simple builder for {@link ScheduleInfo}. */ public static class Builder { - @NonNull private String mTitle; - @NonNull private String mSummary; - @NonNull private Intent mIntent; /** diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java index a423e475d357..28d5f07cc51c 100644 --- a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java +++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/SchedulesProvider.java @@ -21,19 +21,18 @@ import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.SystemProperties; +import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.ArrayList; -import java.util.List; import java.util.stream.Collectors; /** - * This provider is a bridge for client apps to provide the schedule data. - * Client provider needs to implement their {@link #getScheduleInfoList()} and returns a list of - * {@link ScheduleInfo}. + * A bridge for client apps to provide the schedule data. Client provider needs to implement + * {@link #getScheduleInfoList()} returning a list of {@link ScheduleInfo}. */ public abstract class SchedulesProvider extends ContentProvider { public static final String METHOD_GENERATE_SCHEDULE_INFO_LIST = "generateScheduleInfoList"; @@ -46,9 +45,8 @@ public abstract class SchedulesProvider extends ContentProvider { } @Override - public final Cursor query( - Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { + public final Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { throw new UnsupportedOperationException("Query operation is not supported currently."); } @@ -74,18 +72,24 @@ public abstract class SchedulesProvider extends ContentProvider { } /** - * Return the list of the schedule information. - * - * @return a list of the {@link ScheduleInfo}. + * Returns the list of the schedule information. */ public abstract ArrayList<ScheduleInfo> getScheduleInfoList(); /** - * Returns a bundle which contains a list of {@link ScheduleInfo} and data types: - * scheduleInfoList : ArrayList<ScheduleInfo> + * Returns a bundle which contains a list of {@link ScheduleInfo}s: + * + * <ul> + * <li>scheduleInfoList: ArrayList<ScheduleInfo> + * </ul> */ @Override public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) { + if (!TextUtils.equals(getCallingPackage(), + getContext().getText(R.string.config_schedules_provider_caller_package))) { + return null; + } + final Bundle bundle = new Bundle(); if (METHOD_GENERATE_SCHEDULE_INFO_LIST.equals(method)) { final ArrayList<ScheduleInfo> scheduleInfoList = filterInvalidData( @@ -98,36 +102,40 @@ public abstract class SchedulesProvider extends ContentProvider { } /** - * To filter the invalid schedule info. + * Filters our invalid schedule infos from {@code schedulesInfoList}. * - * @param scheduleInfoList The list of the {@link ScheduleInfo}. - * @return The valid list of the {@link ScheduleInfo}. + * @return valid {@link SchedulesInfo}s if {@code schedulesInfoList} is not null. Otherwise, + * null. */ - private ArrayList<ScheduleInfo> filterInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) { + @Nullable + private ArrayList<ScheduleInfo> filterInvalidData( + @Nullable ArrayList<ScheduleInfo> scheduleInfoList) { if (scheduleInfoList == null) { Log.d(TAG, "package : " + getContext().getPackageName() + " has no scheduling data."); return null; } // Dump invalid data in debug mode. if (SystemProperties.getInt("ro.debuggable", 0) == 1) { - new Thread(() -> { - dumpInvalidData(scheduleInfoList); - }).start(); + dumpInvalidData(scheduleInfoList); } - final List<ScheduleInfo> filteredList = scheduleInfoList + return scheduleInfoList .stream() - .filter(scheduleInfo -> scheduleInfo.isValid()) - .collect(Collectors.toList()); - - return new ArrayList<>(filteredList); + .filter(ScheduleInfo::isValid) + .collect(Collectors.toCollection(ArrayList::new)); } private void dumpInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) { - Log.d(TAG, "package : " + getContext().getPackageName() - + " provided some scheduling data are invalid."); - scheduleInfoList + final boolean hasInvalidData = scheduleInfoList .stream() - .filter(scheduleInfo -> !scheduleInfo.isValid()) - .forEach(scheduleInfo -> Log.d(TAG, scheduleInfo.toString())); + .anyMatch(scheduleInfo -> !scheduleInfo.isValid()); + + if (hasInvalidData) { + Log.w(TAG, "package : " + getContext().getPackageName() + + " provided some scheduling data that are invalid."); + scheduleInfoList + .stream() + .filter(scheduleInfo -> !scheduleInfo.isValid()) + .forEach(scheduleInfo -> Log.w(TAG, scheduleInfo.toString())); + } } } diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml index 5e8779fa289a..88c6185a53e7 100644 --- a/packages/SettingsLib/res/values/colors.xml +++ b/packages/SettingsLib/res/values/colors.xml @@ -39,4 +39,7 @@ <color name="dark_mode_icon_color_single_tone">#99000000</color> <color name="light_mode_icon_color_single_tone">#ffffff</color> + + <!-- Yellow 600, used for highlighting "important" conversations in settings & notifications --> + <color name="important_conversation">#f9ab00</color> </resources> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 6d11461d6cfa..e8e1d0b01471 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -892,10 +892,10 @@ <!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] --> <string name="enable_gpu_debug_layers_summary">Allow loading GPU debug layers for debug apps</string> - <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=30] --> + <!-- UI debug setting: enable verbose vendor logging [CHAR LIMIT=60] --> <string name="enable_verbose_vendor_logging">Enable verbose vendor logging</string> - <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=100] --> - <string name="enable_verbose_vendor_logging_summary">Allow additional vendor logs to be included in bug reports, may contain private information</string> + <!-- UI debug setting: enable verbose vendor logging summary [CHAR LIMIT=NONE] --> + <string name="enable_verbose_vendor_logging_summary">Include additional device-specific vendor logs in bug reports, which may contain private information, use more battery, and/or use more storage.</string> <!-- UI debug setting: scaling factor for window animations [CHAR LIMIT=25] --> <string name="window_animation_scale_title">Window animation scale</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 1ebe91736ba1..c9c847ff7194 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -164,7 +164,9 @@ public class A2dpProfile implements LocalBluetoothProfile { if (mBluetoothAdapter == null) { return false; } - return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_AUDIO); + return device == null + ? mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_AUDIO) + : mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_AUDIO); } public BluetoothDevice getActiveDevice() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java index 9dfc4d986745..9dd329ed7cd7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java @@ -125,7 +125,10 @@ public class HeadsetProfile implements LocalBluetoothProfile { if (mBluetoothAdapter == null) { return false; } - return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_PHONE_CALL); + + return device == null + ? mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_PHONE_CALL) + : mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_PHONE_CALL); } public BluetoothDevice getActiveDevice() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index a3b68b4b90b3..d17f242d5d63 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -162,7 +162,9 @@ public class HearingAidProfile implements LocalBluetoothProfile { if (mBluetoothAdapter == null) { return false; } - return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_ALL); + return device == null + ? mBluetoothAdapter.removeActiveDevice(ACTIVE_DEVICE_ALL) + : mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_ALL); } public List<BluetoothDevice> getActiveDevices() { diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index f69e4f5d7689..3ae9e1ed78c3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -15,9 +15,15 @@ */ package com.android.settingslib.media; -import static android.media.MediaRoute2Info.DEVICE_TYPE_BLUETOOTH; -import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV; -import static android.media.MediaRoute2Info.DEVICE_TYPE_UNKNOWN; +import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP; +import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_GROUP; +import static android.media.MediaRoute2Info.TYPE_HEARING_AID; +import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; +import static android.media.MediaRoute2Info.TYPE_UNKNOWN; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; import android.app.Notification; import android.bluetooth.BluetoothAdapter; @@ -165,6 +171,26 @@ public class InfoMediaManager extends MediaManager { } /** + * Release session to stop playing media on MediaDevice. + */ + boolean releaseSession() { + if (TextUtils.isEmpty(mPackageName)) { + Log.w(TAG, "releaseSession() package name is null or empty!"); + return false; + } + + final RoutingSessionInfo info = getRoutingSessionInfo(); + if (info != null) { + mRouterManager.getControllerForSession(info).release(); + return true; + } + + Log.w(TAG, "releaseSession() Ignoring release session : " + mPackageName); + + return false; + } + + /** * Get the MediaDevice list that can be added to current media. * * @return list of MediaDevice @@ -298,7 +324,9 @@ public class InfoMediaManager extends MediaManager { private void buildAllRoutes() { for (MediaRoute2Info route : mRouterManager.getAllRoutes()) { - addMediaDevice(route); + if (route.isSystemRoute()) { + addMediaDevice(route); + } } } @@ -309,27 +337,29 @@ public class InfoMediaManager extends MediaManager { } private void addMediaDevice(MediaRoute2Info route) { - final int deviceType = route.getDeviceType(); + final int deviceType = route.getType(); MediaDevice mediaDevice = null; switch (deviceType) { - case DEVICE_TYPE_UNKNOWN: + case TYPE_UNKNOWN: + case TYPE_REMOTE_TV: + case TYPE_REMOTE_SPEAKER: + case TYPE_GROUP: //TODO(b/148765806): use correct device type once api is ready. - final String defaultRoute = "DEFAULT_ROUTE"; - if (TextUtils.equals(defaultRoute, route.getOriginalId())) { - mediaDevice = - new PhoneMediaDevice(mContext, mRouterManager, route, mPackageName); - } else { - mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route, - mPackageName); - if (!TextUtils.isEmpty(mPackageName) - && TextUtils.equals(route.getClientPackageName(), mPackageName)) { - mCurrentConnectedDevice = mediaDevice; - } + mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route, + mPackageName); + if (!TextUtils.isEmpty(mPackageName) + && TextUtils.equals(route.getClientPackageName(), mPackageName)) { + mCurrentConnectedDevice = mediaDevice; } break; - case DEVICE_TYPE_REMOTE_TV: + case TYPE_BUILTIN_SPEAKER: + case TYPE_WIRED_HEADSET: + case TYPE_WIRED_HEADPHONES: + mediaDevice = + new PhoneMediaDevice(mContext, mRouterManager, route, mPackageName); break; - case DEVICE_TYPE_BLUETOOTH: + case TYPE_HEARING_AID: + case TYPE_BLUETOOTH_A2DP: final BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getOriginalId()); final CachedBluetoothDevice cachedDevice = diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 617da6e0fcd0..c70811f1f20e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -282,6 +282,13 @@ public class LocalMediaManager implements BluetoothCallback { } /** + * Release session to stop playing media on MediaDevice. + */ + public boolean releaseSession() { + return mInfoMediaManager.releaseSession(); + } + + /** * Get the MediaDevice list that has been selected to current media. * * @return list of MediaDevice diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java index 885b7d396a6c..9dc454f53834 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java @@ -15,32 +15,48 @@ */ package com.android.settingslib.notification; +import android.annotation.ColorInt; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; -import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.drawable.BitmapDrawable; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.util.IconDrawableFactory; +import android.util.Log; import com.android.launcher3.icons.BaseIconFactory; -import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.icons.ShadowGenerator; +import com.android.settingslib.R; /** * Factory for creating normalized conversation icons. * We are not using Launcher's IconFactory because conversation rendering only runs on the UI - * thread, so there is no need to manage a pool across multiple threads. + * thread, so there is no need to manage a pool across multiple threads. Launcher's rendering + * also includes shadows, which are only appropriate on top of wallpaper, not embedded in UI. */ public class ConversationIconFactory extends BaseIconFactory { + // Geometry of the various parts of the design. All values are 1dp on a 48x48dp icon grid. + // Space is left around the "head" (main avatar) for + // ........ + // .HHHHHH. + // .HHHrrrr + // .HHHrBBr + // ....rrrr + + private static final float BASE_ICON_SIZE = 48f; + private static final float RING_STROKE_WIDTH = 2f; + private static final float HEAD_SIZE = BASE_ICON_SIZE - RING_STROKE_WIDTH * 2 - 2; // 40 + private static final float BADGE_SIZE = HEAD_SIZE * 0.4f; // 16 final LauncherApps mLauncherApps; final PackageManager mPackageManager; final IconDrawableFactory mIconDrawableFactory; + private int mImportantConversationColor; public ConversationIconFactory(Context context, LauncherApps la, PackageManager pm, IconDrawableFactory iconDrawableFactory, int iconSizePx) { @@ -49,65 +65,156 @@ public class ConversationIconFactory extends BaseIconFactory { mLauncherApps = la; mPackageManager = pm; mIconDrawableFactory = iconDrawableFactory; + mImportantConversationColor = context.getResources().getColor( + R.color.important_conversation, null); } - private int getBadgeSize() { - return mContext.getResources().getDimensionPixelSize( - com.android.launcher3.icons.R.dimen.profile_badge_size); - } /** * Returns the conversation info drawable */ - private Drawable getConversationDrawable(ShortcutInfo shortcutInfo) { + private Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) { return mLauncherApps.getShortcutIconDrawable(shortcutInfo, mFillResIconDpi); } /** - * Get the {@link Drawable} that represents the app icon + * Get the {@link Drawable} that represents the app icon, badged with the work profile icon + * if appropriate. */ - private Drawable getBadgedIcon(String packageName, int userId) { + private Drawable getAppBadge(String packageName, int userId) { + Drawable badge = null; try { final ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser( packageName, PackageManager.GET_META_DATA, userId); - return mIconDrawableFactory.getBadgedIcon(appInfo, userId); + badge = mIconDrawableFactory.getBadgedIcon(appInfo, userId); } catch (PackageManager.NameNotFoundException e) { - return mPackageManager.getDefaultActivityIcon(); + badge = mPackageManager.getDefaultActivityIcon(); } + return badge; } /** - * Turns a Drawable into a Bitmap + * Returns a {@link Drawable} for the entire conversation. The shortcut icon will be badged + * with the launcher icon of the app specified by packageName. */ - BitmapInfo toBitmap(Drawable userBadgedAppIcon) { - Bitmap bitmap = createIconBitmap( - userBadgedAppIcon, 1f, getBadgeSize()); - - Canvas c = new Canvas(); - ShadowGenerator shadowGenerator = new ShadowGenerator(getBadgeSize()); - c.setBitmap(bitmap); - shadowGenerator.recreateIcon(Bitmap.createBitmap(bitmap), c); - return createIconBitmap(bitmap); + public Drawable getConversationDrawable(ShortcutInfo info, String packageName, int uid, + boolean important) { + return getConversationDrawable(getBaseIconDrawable(info), packageName, uid, important); } /** - * Returns a {@link BitmapInfo} for the entire conversation icon including the badge. + * Returns a {@link Drawable} for the entire conversation. The drawable will be badged + * with the launcher icon of the app specified by packageName. */ - public Bitmap getConversationBitmap(ShortcutInfo info, String packageName, int uid) { - return getConversationBitmap(getConversationDrawable(info), packageName, uid); + public Drawable getConversationDrawable(Drawable baseIcon, String packageName, int uid, + boolean important) { + return new ConversationIconDrawable(baseIcon, + getAppBadge(packageName, UserHandle.getUserId(uid)), + mIconBitmapSize, + mImportantConversationColor, + important); } /** - * Returns a {@link BitmapInfo} for the entire conversation icon including the badge. + * Custom Drawable that overlays a badge drawable (e.g. notification small icon or app icon) on + * a base icon (conversation/person avatar), plus decorations indicating conversation + * importance. */ - public Bitmap getConversationBitmap(Drawable baseIcon, String packageName, int uid) { - int userId = UserHandle.getUserId(uid); - Drawable badge = getBadgedIcon(packageName, userId); - BitmapInfo iconInfo = createBadgedIconBitmap(baseIcon, - UserHandle.of(userId), - true /* shrinkNonAdaptiveIcons */); - - badgeWithDrawable(iconInfo.icon, - new BitmapDrawable(mContext.getResources(), toBitmap(badge).icon)); - return iconInfo.icon; + public static class ConversationIconDrawable extends Drawable { + private Drawable mBaseIcon; + private Drawable mBadgeIcon; + private int mIconSize; + private Paint mRingPaint; + private boolean mShowRing; + + public ConversationIconDrawable(Drawable baseIcon, + Drawable badgeIcon, + int iconSize, + @ColorInt int ringColor, + boolean showImportanceRing) { + mBaseIcon = baseIcon; + mBadgeIcon = badgeIcon; + mIconSize = iconSize; + mShowRing = showImportanceRing; + mRingPaint = new Paint(); + mRingPaint.setStyle(Paint.Style.STROKE); + mRingPaint.setColor(ringColor); + } + + /** + * Show or hide the importance ring. + */ + public void setImportant(boolean important) { + if (important != mShowRing) { + mShowRing = important; + invalidateSelf(); + } + } + + @Override + public int getIntrinsicWidth() { + return mIconSize; + } + + @Override + public int getIntrinsicHeight() { + return mIconSize; + } + + // Similar to badgeWithDrawable, but relying on the bounds of each underlying drawable + @Override + public void draw(Canvas canvas) { + final Rect bounds = getBounds(); + + // scale to our internal 48x48 grid + final float scale = bounds.width() / BASE_ICON_SIZE; + final int centerX = bounds.centerX(); + final int centerY = bounds.centerX(); + final int ringStrokeWidth = (int) (RING_STROKE_WIDTH * scale); + final int headSize = (int) (HEAD_SIZE * scale); + final int badgeSize = (int) (BADGE_SIZE * scale); + + if (mBaseIcon != null) { + mBaseIcon.setBounds( + centerX - headSize / 2, + centerY - headSize / 2, + centerX + headSize / 2, + centerY + headSize / 2); + mBaseIcon.draw(canvas); + } else { + Log.w("ConversationIconFactory", "ConversationIconDrawable has null base icon"); + } + if (mBadgeIcon != null) { + mBadgeIcon.setBounds( + bounds.right - badgeSize - ringStrokeWidth, + bounds.bottom - badgeSize - ringStrokeWidth, + bounds.right - ringStrokeWidth, + bounds.bottom - ringStrokeWidth); + mBadgeIcon.draw(canvas); + } else { + Log.w("ConversationIconFactory", "ConversationIconDrawable has null badge icon"); + } + if (mShowRing) { + mRingPaint.setStrokeWidth(ringStrokeWidth); + final float radius = badgeSize * 0.5f + ringStrokeWidth * 0.5f; // stroke outside + final float cx = bounds.right - badgeSize * 0.5f - ringStrokeWidth; + final float cy = bounds.bottom - badgeSize * 0.5f - ringStrokeWidth; + canvas.drawCircle(cx, cy, radius, mRingPaint); + } + } + + @Override + public void setAlpha(int alpha) { + // unimplemented + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + // unimplemented + } + + @Override + public int getOpacity() { + return 0; + } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 3f55ceaad29a..8bf48e59165e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -68,6 +68,7 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { private WifiInfo mWifiInfo; public boolean enabled; + public boolean isCaptivePortal; public int state; public boolean connected; public String ssid; @@ -155,9 +156,11 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { private void updateStatusLabel() { final NetworkCapabilities networkCapabilities = mConnectivityManager.getNetworkCapabilities(mWifiManager.getCurrentNetwork()); + isCaptivePortal = false; if (networkCapabilities != null) { if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) { statusLabel = mContext.getString(R.string.wifi_status_sign_in_required); + isCaptivePortal = true; return; } else if (networkCapabilities.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)) { statusLabel = mContext.getString(R.string.wifi_limited_connection); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index d23364952357..0e6a60bf47c1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -68,7 +68,8 @@ public class WifiUtils { for (int reason = 0; reason <= getMaxNetworkSelectionDisableReason(); reason++) { if (networkStatus.getDisableReasonCounter(reason) != 0) { summary.append(" ") - .append(NetworkSelectionStatus.getNetworkDisableReasonString(reason)) + .append(NetworkSelectionStatus + .getNetworkSelectionDisableReasonString(reason)) .append("=") .append(networkStatus.getDisableReasonCounter(reason)); } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java index c555cbec4bab..414c39bc0ce9 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java @@ -203,4 +203,10 @@ public class A2dpProfileTest { assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo( String.format(KNOWN_CODEC_LABEL, config.getCodecName())); } + + @Test + public void setActiveDevice_returnTrue() { + assertThat(mProfile.setActiveDevice(null)).isTrue(); + assertThat(mProfile.setActiveDevice(mDevice)).isTrue(); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java index 9adef8287355..30182c476855 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HeadsetProfileTest.java @@ -75,4 +75,10 @@ public class HeadsetProfileTest { assertThat(mProfile.getAudioState(mBluetoothDevice)). isEqualTo(BluetoothHeadset.STATE_AUDIO_CONNECTED); } + + @Test + public void setActiveDevice_returnTrue() { + assertThat(mProfile.setActiveDevice(null)).isTrue(); + assertThat(mProfile.setActiveDevice(mBluetoothDevice)).isTrue(); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidProfileTest.java new file mode 100644 index 000000000000..be3a51788d24 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidProfileTest.java @@ -0,0 +1,77 @@ +/* + * 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.settingslib.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHearingAid; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class}) +public class HearingAidProfileTest { + @Mock + private CachedBluetoothDeviceManager mDeviceManager; + @Mock + private LocalBluetoothProfileManager mProfileManager; + @Mock + private BluetoothHearingAid mService; + @Mock + private CachedBluetoothDevice mCachedBluetoothDevice; + @Mock + private BluetoothDevice mBluetoothDevice; + + private BluetoothProfile.ServiceListener mServiceListener; + private HearingAidProfile mProfile; + private ShadowBluetoothAdapter mShadowBluetoothAdapter; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + Context context = spy(RuntimeEnvironment.application); + mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); + + when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); + + mProfile = new HearingAidProfile(context, mDeviceManager, mProfileManager); + mServiceListener = mShadowBluetoothAdapter.getServiceListener(); + mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mService); + } + + @Test + public void setActiveDevice_returnTrue() { + assertThat(mProfile.setActiveDevice(null)).isTrue(); + assertThat(mProfile.setActiveDevice(mBluetoothDevice)).isTrue(); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java index 9668629dea8c..edb121b762a7 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java @@ -96,6 +96,7 @@ public class InfoMediaManagerTest { final MediaRoute2Info info = mock(MediaRoute2Info.class); when(info.getId()).thenReturn(TEST_ID); when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(info.isSystemRoute()).thenReturn(true); final List<MediaRoute2Info> routes = new ArrayList<>(); routes.add(info); @@ -166,6 +167,7 @@ public class InfoMediaManagerTest { final MediaRoute2Info info = mock(MediaRoute2Info.class); when(info.getId()).thenReturn(TEST_ID); when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(info.isSystemRoute()).thenReturn(true); final List<MediaRoute2Info> routes = new ArrayList<>(); routes.add(info); @@ -221,6 +223,7 @@ public class InfoMediaManagerTest { final MediaRoute2Info info = mock(MediaRoute2Info.class); when(info.getId()).thenReturn(TEST_ID); when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(info.isSystemRoute()).thenReturn(true); final List<MediaRoute2Info> routes = new ArrayList<>(); routes.add(info); @@ -438,4 +441,23 @@ public class InfoMediaManagerTest { assertThat(mInfoMediaManager.getSessionVolume()).isEqualTo(-1); } + + @Test + public void releaseSession_packageNameIsNull_returnFalse() { + mInfoMediaManager.mPackageName = null; + + assertThat(mInfoMediaManager.releaseSession()).isFalse(); + } + + @Test + public void releaseSession_removeSuccessfully_returnTrue() { + final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>(); + final RoutingSessionInfo info = mock(RoutingSessionInfo.class); + routingSessionInfos.add(info); + + mShadowRouter2Manager.setRoutingSessions(routingSessionInfos); + when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME); + + assertThat(mInfoMediaManager.releaseSession()).isTrue(); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java new file mode 100644 index 000000000000..5ec89eddda6e --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java @@ -0,0 +1,98 @@ +/* + * 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.settingslib.schedulesprovider; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Intent; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ScheduleInfoTest { + private static final String TEST_TITLE = "Night Light"; + private static final String TEST_SUMMARY = "Night Light summary"; + private static final String TEST_EMPTY_SUMMARY = ""; + + @Test + public void builder_usedValidArguments_isValid() { + final Intent intent = createTestIntent(); + final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent); + + assertThat(info).isNotNull(); + assertThat(info.isValid()).isTrue(); + } + + @Test + public void builder_useEmptySummary_isInvalid() { + final Intent intent = createTestIntent(); + final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY, intent); + + assertThat(info).isNotNull(); + assertThat(info.isValid()).isFalse(); + } + + @Test + public void builder_intentIsNull_isInvalid() { + final ScheduleInfo info = new ScheduleInfo.Builder() + .setTitle(TEST_TITLE) + .setSummary(TEST_SUMMARY) + .build(); + + assertThat(info).isNotNull(); + assertThat(info.isValid()).isFalse(); + } + + @Test + public void getTitle_setValidTitle_shouldReturnSameCorrectTitle() { + final Intent intent = createTestIntent(); + final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent); + + assertThat(info.getTitle()).isEqualTo(TEST_TITLE); + } + + @Test + public void getSummary_setValidSummary_shouldReturnSameCorrectSummary() { + final Intent intent = createTestIntent(); + final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent); + + assertThat(info.getSummary()).isEqualTo(TEST_SUMMARY); + } + + @Test + public void getIntent_setValidIntent_shouldReturnSameCorrectIntent() { + final Intent intent = createTestIntent(); + final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent); + + assertThat(info.getIntent()).isEqualTo(intent); + } + + private static Intent createTestIntent() { + return new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory( + Intent.CATEGORY_DEFAULT); + } + + private static ScheduleInfo createTestScheduleInfo(String title, String summary, + Intent intent) { + return new ScheduleInfo.Builder() + .setTitle(title) + .setSummary(summary) + .setIntent(intent) + .build(); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java new file mode 100644 index 000000000000..eb2e8e055378 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java @@ -0,0 +1,166 @@ +/* + * 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.settingslib.schedulesprovider; + +import static com.google.common.truth.Truth.assertThat; + +import static org.robolectric.Shadows.shadowOf; + +import android.content.Intent; +import android.os.Bundle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; + +import java.util.ArrayList; + +@RunWith(RobolectricTestRunner.class) +public class SchedulesProviderTest { + private static final String INVALID_PACKAGE = "com.android.sunny"; + private static final String VALID_PACKAGE = "com.android.settings"; + private static final String INVALID_METHOD = "queryTestData"; + private TestSchedulesProvider mProvider; + + @Before + public void setUp() { + mProvider = Robolectric.setupContentProvider(TestSchedulesProvider.class); + shadowOf(mProvider).setCallingPackage(VALID_PACKAGE); + mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo()); + } + + @Test + public void call_invalidCallingPkg_returnNull() { + shadowOf(mProvider).setCallingPackage(INVALID_PACKAGE); + + final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST, + null /* arg */, null /* extras */); + + assertThat(bundle).isNull(); + } + + @Test + public void call_invalidMethod_returnBundleWithoutScheduleInfoData() { + final Bundle bundle = mProvider.call(INVALID_METHOD, null /* arg */, null /* extras */); + + assertThat(bundle).isNotNull(); + assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isFalse(); + } + + @Test + public void call_validMethod_returnScheduleInfoData() { + final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST, + null /* arg */, null /* extras */); + + assertThat(bundle).isNotNull(); + assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue(); + final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList( + SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST); + assertThat(infos).hasSize(1); + } + + @Test + public void call_addTwoValidData_returnScheduleInfoData() { + mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos()); + final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST, + null /* arg */, null /* extras */); + + assertThat(bundle).isNotNull(); + assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue(); + final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList( + SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST); + assertThat(infos).hasSize(2); + } + + @Test + public void call_addTwoValidDataAndOneInvalidData_returnTwoScheduleInfoData() { + mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo()); + final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST, + null /* arg */, null /* extras */); + + assertThat(bundle).isNotNull(); + assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue(); + final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList( + SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST); + assertThat(infos).hasSize(2); + } + + private static class TestSchedulesProvider extends SchedulesProvider { + private ArrayList<ScheduleInfo> mScheduleInfos = new ArrayList<>(); + + @Override + public ArrayList<ScheduleInfo> getScheduleInfoList() { + return mScheduleInfos; + } + + void setScheduleInfos(ArrayList<ScheduleInfo> scheduleInfos) { + mScheduleInfos = scheduleInfos; + } + + private static ArrayList<ScheduleInfo> createOneValidScheduleInfo() { + final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>(); + final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory( + Intent.CATEGORY_DEFAULT); + final ScheduleInfo info = new ScheduleInfo.Builder().setTitle( + "Night Light").setSummary("This a sunny test").setIntent(intent).build(); + scheduleInfos.add(info); + + return scheduleInfos; + } + + private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos() { + final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>(); + Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory( + Intent.CATEGORY_DEFAULT); + ScheduleInfo info = new ScheduleInfo.Builder().setTitle( + "Night Light").setSummary("This a sunny test").setIntent(intent).build(); + scheduleInfos.add(info); + + intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory( + Intent.CATEGORY_DEFAULT); + info = new ScheduleInfo.Builder().setTitle("Display").setSummary( + "Display summary").setIntent(intent).build(); + scheduleInfos.add(info); + + return scheduleInfos; + } + + private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo() { + final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>(); + Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory( + Intent.CATEGORY_DEFAULT); + ScheduleInfo info = new ScheduleInfo.Builder().setTitle( + "Night Light").setSummary("This a sunny test").setIntent(intent).build(); + scheduleInfos.add(info); + + intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory( + Intent.CATEGORY_DEFAULT); + info = new ScheduleInfo.Builder().setTitle("Display").setSummary( + "Display summary").setIntent(intent).build(); + scheduleInfos.add(info); + + intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory( + Intent.CATEGORY_DEFAULT); + info = new ScheduleInfo.Builder().setTitle("").setSummary("Display summary").setIntent( + intent).build(); + scheduleInfos.add(info); + + return scheduleInfos; + } + } +} diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java index 015ce149a9c4..b265d46058be 100644 --- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java +++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java @@ -16,6 +16,10 @@ package com.android.settingslib.testutils.shadow; +import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL; +import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO; +import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL; + import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; @@ -61,4 +65,26 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto public void setMostRecentlyConnectedDevices(List<BluetoothDevice> list) { mMostRecentlyConnectedDevices = list; } + + @Implementation + protected boolean removeActiveDevice(@BluetoothAdapter.ActiveDeviceUse int profiles) { + if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL + && profiles != ACTIVE_DEVICE_ALL) { + return false; + } + return true; + } + + @Implementation + protected boolean setActiveDevice(BluetoothDevice device, + @BluetoothAdapter.ActiveDeviceUse int profiles) { + if (device == null) { + return false; + } + if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL + && profiles != ACTIVE_DEVICE_ALL) { + return false; + } + return true; + } } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 0f2ee6ac8bbd..610165a44626 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -268,6 +268,7 @@ public class SettingsBackupTest { Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS, + Settings.Global.ENHANCED_CONNECTIVITY_ENABLED, Settings.Global.ENHANCED_4G_MODE_ENABLED, Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES, Settings.Global.ERROR_LOGCAT_PREFIX, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 99f8c7dca44f..56d5de473bfc 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -192,7 +192,10 @@ <uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" /> <!-- Permission needed to wipe the device for Test Harness Mode --> <uses-permission android:name="android.permission.ENABLE_TEST_HARNESS_MODE" /> + + <!-- Permissions required to test CompanionDeviceManager teses in CTS --> <uses-permission android:name="android.permission.MANAGE_COMPANION_DEVICES" /> + <uses-permission android:name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS" /> <uses-permission android:name="android.permission.MANAGE_APPOPS" /> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index d126ee0955ea..c76b50bd4e9c 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -615,13 +615,16 @@ public class BugreportProgressService extends Service { + " bugreport parcel file descriptor is null."); return; } - ParcelFileDescriptor screenshotFd = info.getDefaultScreenshotFd(); - if (screenshotFd == null) { - Log.e(TAG, "Failed to start bugreport generation as" - + " screenshot parcel file descriptor is null. Deleting bugreport file"); - FileUtils.closeQuietly(bugreportFd); - info.bugreportFile.delete(); - return; + ParcelFileDescriptor screenshotFd = null; + if (isDefaultScreenshotRequired(bugreportType)) { + screenshotFd = info.getDefaultScreenshotFd(); + if (screenshotFd == null) { + Log.e(TAG, "Failed to start bugreport generation as" + + " screenshot parcel file descriptor is null. Deleting bugreport file"); + FileUtils.closeQuietly(bugreportFd); + info.bugreportFile.delete(); + return; + } } mBugreportManager = (BugreportManager) mContext.getSystemService( @@ -641,10 +644,20 @@ public class BugreportProgressService extends Service { // The binder call didn't go through successfully, so need to close the fds. // If the calls went through API takes ownership. FileUtils.closeQuietly(bugreportFd); - FileUtils.closeQuietly(screenshotFd); + if (screenshotFd != null) { + FileUtils.closeQuietly(screenshotFd); + } } } + private static boolean isDefaultScreenshotRequired( + @BugreportParams.BugreportMode int bugreportType) { + // Modify dumpstate#SetOptionsFromMode as well for default system screenshots. + // We override dumpstate for interactive bugreports. + return bugreportType == BugreportParams.BUGREPORT_MODE_FULL + || bugreportType == BugreportParams.BUGREPORT_MODE_WEAR; + } + private static ParcelFileDescriptor getFd(File file) { try { return ParcelFileDescriptor.open(file, diff --git a/packages/StatementService/AndroidManifest.xml b/packages/StatementService/AndroidManifest.xml index d79d90087ed5..b00c37f92baf 100644 --- a/packages/StatementService/AndroidManifest.xml +++ b/packages/StatementService/AndroidManifest.xml @@ -22,6 +22,7 @@ <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/> + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <application android:label="@string/service_name" diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java index 6650c15d6742..f79cd8625c7c 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java @@ -68,14 +68,14 @@ public interface NotificationPersonExtractorPlugin extends Plugin { public final String key; public final CharSequence name; public final Drawable avatar; - public final PendingIntent clickIntent; + public final Runnable clickRunnable; public PersonData(String key, CharSequence name, Drawable avatar, - PendingIntent clickIntent) { + Runnable clickRunnable) { this.key = key; this.name = name; this.avatar = avatar; - this.clickIntent = clickIntent; + this.clickRunnable = clickRunnable; } } } diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml b/packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml new file mode 100644 index 000000000000..64db25b65a0b --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml @@ -0,0 +1,21 @@ +<!-- + ~ 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?android:attr/colorAccent"/> + <corners + android:radius="?android:attr/dialogCornerRadius" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml index 7964609f62e0..015e9f99212d 100644 --- a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml +++ b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml @@ -16,6 +16,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" - android:color="@color/notification_guts_priority_button_bg_stroke_color_selected" /> + android:color="?android:attr/colorAccent" /> <item android:color="@color/notification_guts_priority_button_bg_stroke_color" /> </selector> diff --git a/packages/SystemUI/res/color/notification_guts_priority_contents.xml b/packages/SystemUI/res/color/notification_guts_priority_contents.xml index 56c43f0e5642..42f01896d7a1 100644 --- a/packages/SystemUI/res/color/notification_guts_priority_contents.xml +++ b/packages/SystemUI/res/color/notification_guts_priority_contents.xml @@ -16,6 +16,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" - android:color="@color/notification_guts_priority_button_content_color_selected" /> + android:color="?android:attr/colorAccent" /> <item android:color="@color/notification_guts_priority_button_content_color" /> </selector> diff --git a/packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml b/packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml new file mode 100644 index 000000000000..4b9219cd6194 --- /dev/null +++ b/packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml @@ -0,0 +1,22 @@ +<!-- + ~ 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. + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?android:attr/colorAccent"/> + <corners + android:bottomRightRadius="360dp" + android:topRightRadius="360dp" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml index 1730dcefe480..2fe6c7b2d1a2 100644 --- a/packages/SystemUI/res/drawable/notification_guts_bg.xml +++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml @@ -16,7 +16,7 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> - <solid android:color="@color/notification_guts_bg_color" /> + <solid android:color="@color/notification_material_background_color" /> <!--The radius is 1dp smaller than the notification one, to avoid aliasing bugs on the corners --> <corners android:radius="1dp" /> </shape> diff --git a/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml b/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml new file mode 100644 index 000000000000..e3d010ee7674 --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?android:attr/colorControlHighlight"> + <item> + <shape> + <solid android:color="@color/qs_user_detail_avatar_frame" /> + + <padding + android:left="1dp" + android:right="1dp" + android:bottom="1dp" + android:top="1dp" /> + + <corners android:radius="48dp" /> + </shape> + </item> +</ripple> diff --git a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml new file mode 100644 index 000000000000..1f38b1ea1da5 --- /dev/null +++ b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- LinearLayout --> +<com.android.systemui.statusbar.policy.KeyguardUserDetailItemView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sysui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="8dp" + android:layout_marginEnd="8dp" + android:gravity="end|center_vertical" + android:clickable="true" + android:background="@drawable/rounded_user_switcher_bg" + sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" + sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> + <TextView android:id="@+id/user_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="13dp" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" + /> + <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" + android:layout_width="@dimen/framed_avatar_size" + android:layout_height="@dimen/framed_avatar_size" + android:contentDescription="@null" + sysui:badgeDiameter="18dp" + sysui:badgeMargin="1dp" /> +</com.android.systemui.statusbar.policy.KeyguardUserDetailItemView> diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml index 82a0115098f2..bfa252c5a14b 100644 --- a/packages/SystemUI/res/layout/app_ops_info.xml +++ b/packages/SystemUI/res/layout/app_ops_info.xml @@ -26,7 +26,7 @@ android:orientation="vertical" android:paddingStart="@*android:dimen/notification_content_margin_start" android:paddingEnd="@*android:dimen/notification_content_margin_end" - android:background="@color/notification_guts_bg_color" + android:background="@color/notification_material_background_color" android:theme="@*android:style/Theme.DeviceDefault.Light"> <!-- Package Info --> diff --git a/packages/SystemUI/res/layout/bubble_stack_user_education.xml b/packages/SystemUI/res/layout/bubble_stack_user_education.xml new file mode 100644 index 000000000000..81b28e612993 --- /dev/null +++ b/packages/SystemUI/res/layout/bubble_stack_user_education.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/user_education_view" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:paddingTop="48dp" + android:paddingBottom="48dp" + android:paddingStart="@dimen/bubble_stack_user_education_side_inset" + android:paddingEnd="16dp" + android:layout_marginEnd="24dp" + android:orientation="vertical" + android:background="@drawable/bubble_stack_user_education_bg"> + + <TextView + android:id="@+id/user_education_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingBottom="16dp" + android:fontFamily="@*android:string/config_bodyFontFamilyMedium" + android:maxLines="1" + android:text="@string/bubbles_user_education_title" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/> + + <TextView + android:id="@+id/user_education_description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/bubbles_user_education_description" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/> + +</LinearLayout> diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml new file mode 100644 index 000000000000..0cabc3245152 --- /dev/null +++ b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<com.android.systemui.bubbles.BubbleManageEducationView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/manage_education_view" + android:orientation="vertical" + android:layout_height="wrap_content" + android:layout_width="@dimen/bubbles_manage_education_width"> + + <TextView + android:id="@+id/user_education_description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:text="@string/bubbles_user_education_manage" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2" + android:background="@drawable/bubble_manage_user_education_bg" + /> + + <View + android:id="@+id/user_education_pointer" + android:layout_width="@dimen/bubble_pointer_width" + android:layout_height="@dimen/bubble_pointer_height" + /> + + </LinearLayout> +</com.android.systemui.bubbles.BubbleManageEducationView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml index a7379bedebef..6533c18a41a9 100644 --- a/packages/SystemUI/res/layout/controls_management.xml +++ b/packages/SystemUI/res/layout/controls_management.xml @@ -70,12 +70,14 @@ android:layout_height="match_parent" android:padding="4dp"> - <TextView + <Button + android:id="@+id/other_apps" + android:visibility="gone" android:layout_width="wrap_content" android:layout_height="match_parent" + android:gravity="center_vertical" android:text="See other apps" - android:textAppearance="@style/TextAppearance.Control.Title" - android:textColor="?android:attr/colorPrimary" + style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"/> @@ -85,6 +87,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:text="Done" + style="@*android:style/Widget.DeviceDefault.Button.Colored" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"/> diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml index 62056e60372d..aab32f45e77a 100644 --- a/packages/SystemUI/res/layout/controls_management_favorites.xml +++ b/packages/SystemUI/res/layout/controls_management_favorites.xml @@ -14,97 +14,26 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<androidx.constraintlayout.widget.ConstraintLayout +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView - android:id="@+id/error_message" + android:id="@+id/status_message" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/controls_management_list_margin" - android:text="@string/controls_favorite_load_error" android:textAppearance="?android:attr/textAppearanceSmall" - android:visibility="gone" android:gravity="center_horizontal" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="parent" - app:layout_constraintBottom_toTopOf="@id/text_favorites" /> - <TextView - android:id="@+id/text_favorites" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/controls_management_list_margin" - android:text="@string/controls_favorite_header_favorites" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textAllCaps="true" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintBottom_toTopOf="@id/divider1" - app:layout_constraintTop_toBottomOf="@id/error_message" - /> - - <View - android:id="@+id/divider1" - android:layout_width="match_parent" - android:layout_height="@dimen/controls_app_divider_height" - android:layout_gravity="center_horizontal|top" - android:background="?android:attr/listDivider" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@id/listFavorites" - app:layout_constraintTop_toBottomOf="@id/text_favorites" - /> - - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/listFavorites" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginTop="@dimen/controls_management_list_margin" - android:nestedScrollingEnabled="false" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@id/text_all" - app:layout_constraintTop_toBottomOf="@id/divider1"/> - - <TextView - android:id="@+id/text_all" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/controls_management_list_margin" - android:text="@string/controls_favorite_header_all" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textAllCaps="true" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintBottom_toTopOf="@id/divider2" - app:layout_constraintTop_toBottomOf="@id/listFavorites" - /> - - <View - android:id="@+id/divider2" - android:layout_width="match_parent" - android:layout_height="@dimen/controls_app_divider_height" - android:layout_gravity="center_horizontal|top" - android:background="?android:attr/listDivider" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toTopOf="@id/listAll" - app:layout_constraintTop_toBottomOf="@id/text_all" - /> - <androidx.recyclerview.widget.RecyclerView android:id="@+id/listAll" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="@dimen/controls_management_list_margin" - android:nestedScrollingEnabled="false" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/divider2"/> + android:nestedScrollingEnabled="false"/> -</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index 0b74a11a1a0f..a76f96115fa9 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -32,10 +32,10 @@ android:alpha="0"/> <HorizontalScrollView android:id="@+id/global_screenshot_actions_container" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="bottom|center" - android:elevation="3dp" + android:layout_gravity="bottom|left" + android:elevation="1dp" android:fillViewport="true" android:layout_marginHorizontal="@dimen/screenshot_action_container_margin_horizontal" android:gravity="center" @@ -63,7 +63,7 @@ android:id="@+id/global_screenshot_dismiss_button" android:layout_width="@dimen/screenshot_dismiss_button_tappable_size" android:layout_height="@dimen/screenshot_dismiss_button_tappable_size" - android:elevation="9dp" + android:elevation="7dp" android:visibility="gone"> <ImageView android:layout_width="match_parent" @@ -76,7 +76,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:src="@android:color/white" - android:elevation="8dp" + android:elevation="@dimen/screenshot_preview_elevation" android:visibility="gone"/> <com.android.systemui.screenshot.ScreenshotSelectorView android:id="@+id/global_screenshot_selector" diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml index 79867a16b243..6b94befad0f8 100644 --- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml +++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml @@ -19,7 +19,7 @@ android:id="@+id/global_screenshot_action_chip" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal" + android:layout_marginRight="@dimen/screenshot_action_chip_margin_right" android:layout_gravity="center" android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical" android:background="@drawable/action_chip_background" @@ -35,7 +35,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/screenshot_action_chip_padding_end" + android:fontFamily="@*android:string/config_headlineFontFamilyMedium" android:textSize="@dimen/screenshot_action_chip_text_size" - android:textStyle="bold" android:textColor="@color/global_screenshot_button_text"/> </com.android.systemui.screenshot.ScreenshotActionChip> diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml index fb38e1c6dc6b..b1e51659817e 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml +++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml @@ -27,8 +27,6 @@ android:gravity="center_vertical" android:clickable="true" android:background="@drawable/ripple_drawable" - android:clipChildren="false" - android:clipToPadding="false" sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> <TextView android:id="@+id/user_name" diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 87de9d4d3b51..5d03eee11f75 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -24,8 +24,7 @@ android:clipChildren="false" android:clipToPadding="true" android:orientation="vertical" - android:paddingStart="@*android:dimen/notification_content_margin_start" - android:background="@color/notification_guts_bg_color"> + android:paddingStart="@*android:dimen/notification_content_margin_start"> <!-- Package Info --> <RelativeLayout diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml index ffe2eee80447..c350ed22b765 100644 --- a/packages/SystemUI/res/layout/notification_snooze.xml +++ b/packages/SystemUI/res/layout/notification_snooze.xml @@ -21,7 +21,7 @@ android:layout_height="wrap_content" android:orientation="vertical" android:clickable="true" - android:background="@color/notification_guts_bg_color" + android:background="@color/notification_material_background_color" android:theme="@style/Theme.SystemUI"> <RelativeLayout diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml index 887878631de7..46a7cf6440bb 100644 --- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml +++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml @@ -17,6 +17,7 @@ <com.android.systemui.qs.PagedTileLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/qs_pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 4fae3c500a45..f8db97dbf800 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -24,7 +24,6 @@ android:layout_width="match_parent" android:layout_height="@dimen/status_bar_height" android:id="@+id/status_bar" - android:background="@drawable/system_bar_background" android:orientation="vertical" android:focusable="false" android:descendantFocusability="afterDescendants" diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml index 36ba66af5729..5a1e5c439724 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml @@ -33,8 +33,8 @@ android:layout_height="wrap_content" android:layout_gravity="start" android:focusable="true" - android:contentDescription="@string/accessibility_manage_notification" - android:text="@string/manage_notifications_text" + android:contentDescription="@string/manage_notifications_history_text" + android:text="@string/manage_notifications_history_text" /> <com.android.systemui.statusbar.notification.row.FooterViewButton style="@style/TextAppearance.NotificationSectionHeaderButton" diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index 8fee2cf9597e..7142929bab64 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -28,5 +28,6 @@ <FrameLayout android:id="@+id/status_bar_container" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + android:background="@drawable/system_bar_background" /> </com.android.systemui.statusbar.phone.StatusBarWindowView> diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index f3b72bf23757..6fb5590df6ed 100644 --- a/packages/SystemUI/res/layout/system_icons.xml +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -26,6 +26,7 @@ android:layout_weight="1" android:layout_height="match_parent" android:paddingEnd="@dimen/signal_cluster_battery_padding" + android:paddingTop="@dimen/status_bar_padding_top" android:gravity="center_vertical" android:orientation="horizontal"/> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index 9a66e8bc8791..9b0fe465deee 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -39,23 +39,16 @@ <!-- The color of the ripples on the untinted notifications --> <color name="notification_ripple_untinted_color">#30ffffff</color> - <!-- The "inside" of a notification, reached via longpress --> - <color name="notification_guts_bg_color">@color/GM2_grey_900</color> - <!-- The color of the text inside a notification --> <color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color> <color name="notification_guts_link_icon_tint">@color/GM2_grey_500</color> <color name="notification_guts_sub_text_color">@color/GM2_grey_300</color> <color name="notification_guts_header_text_color">@color/GM2_grey_200</color> - <color name="notification_guts_info_button_color">@color/GM2_blue_300</color> <color name="notification_guts_priority_button_content_color">@color/GM2_grey_500</color> - <color name="notification_guts_priority_button_content_color_selected">@color/GM2_blue_300</color> <color name="notification_guts_priority_button_bg_fill_color">@color/transparent</color> <color name="notification_guts_priority_button_bg_fill_color_selected">@color/GM2_grey_800</color> <color name="notification_guts_priority_button_bg_stroke_color">@color/GM2_grey_700</color> - <color name="notification_guts_priority_button_bg_stroke_color_selected">@color/GM2_blue_300</color> - <color name="notification_section_header_label_color">@color/GM2_grey_200</color> <color name="notification_section_clear_all_btn_color">@color/GM2_grey_500</color> <color name="notification_channel_dialog_separator">@color/GM2_grey_700</color> diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml index 23b64e34a939..b375364fdab9 100644 --- a/packages/SystemUI/res/values-sw600dp/styles.xml +++ b/packages/SystemUI/res/values-sw600dp/styles.xml @@ -22,4 +22,28 @@ <style name="UserDetailView"> <item name="numColumns">4</item> </style> + + <style name="TextAppearance.StatusBar.Expanded.UserSwitcher"> + <item name="android:textSize">@dimen/kg_user_switcher_text_size</item> + <item name="android:textStyle">normal</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:textColor">?attr/wallpaperTextColor</item> + </style> + + <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> + <item name="android:fontWeight">700</item> + <item name="android:textStyle">bold</item> + <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> + </style> + + <style name="TextAppearance.QS.UserSwitcher"> + <item name="android:textSize">@dimen/qs_detail_item_primary_text_size</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + </style> + + <style name="TextAppearance.QS.UserSwitcher.Activated"> + <item name="android:fontWeight">700</item> + <item name="android:textStyle">bold</item> + </style> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 43ceb4ecaee8..73e49cee6a8b 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -88,21 +88,16 @@ <!-- The color of the text inside a notification --> <color name="notification_primary_text_color">@*android:color/notification_primary_text_color_light</color> - <!-- The "inside" of a notification, reached via longpress --> - <color name="notification_guts_bg_color">@color/GM2_grey_50</color> <color name="notification_guts_link_icon_tint">@color/GM2_grey_700</color> <color name="notification_guts_sub_text_color">@color/GM2_grey_700</color> <color name="notification_guts_header_text_color">@color/GM2_grey_900</color> <color name="notification_silence_color">#FF32c1de</color> <color name="notification_alert_color">#FFF87B2B</color> - <color name="notification_guts_info_button_color">@color/GM2_blue_700</color> <color name="notification_guts_priority_button_content_color">@color/GM2_grey_700</color> - <color name="notification_guts_priority_button_content_color_selected">@color/GM2_blue_700</color> <color name="notification_guts_priority_button_bg_fill_color">@color/transparent</color> <color name="notification_guts_priority_button_bg_fill_color_selected">#FFFFFF</color> <color name="notification_guts_priority_button_bg_stroke_color">@color/GM2_grey_300</color> - <color name="notification_guts_priority_button_bg_stroke_color_selected">@color/GM2_blue_600</color> <color name="notification_section_header_label_color">@color/GM2_grey_900</color> <color name="notification_section_clear_all_btn_color">@color/GM2_grey_700</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 8de2df592eda..27ffcee2a2dc 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -201,6 +201,13 @@ always-on display) --> <string name="doze_brightness_sensor_type" translatable="false"></string> + <!-- Override value to use for proximity sensor. --> + <string name="proximity_sensor_type" translatable="false"></string> + + <!-- If using proximity_sensor_type, specifies a threshold value to distinguish near and + far break points. A sensor value less than this is considered "near". --> + <item name="proximity_sensor_threshold" translatable="false" format="float" type="dimen"></item> + <!-- Doze: pulse parameter - how long does it take to fade in? --> <integer name="doze_pulse_duration_in">130</integer> @@ -464,6 +471,9 @@ <!-- Allow dragging the PIP to a location to close it --> <bool name="config_pipEnableDismissDragToEdge">true</bool> + <!-- Allow PIP to resize to a slightly bigger state upon touch/showing the menu --> + <bool name="config_pipEnableResizeForMenu">true</bool> + <!-- SystemUI Plugins that can be loaded on user builds. --> <string-array name="config_pluginWhitelist" translatable="false"> <item>com.android.systemui</item> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 9caaa9f8565d..aefe4a20a496 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -305,7 +305,7 @@ <dimen name="global_screenshot_legacy_bg_padding">20dp</dimen> <dimen name="global_screenshot_bg_padding">20dp</dimen> <dimen name="global_screenshot_x_scale">80dp</dimen> - <dimen name="screenshot_preview_elevation">8dp</dimen> + <dimen name="screenshot_preview_elevation">6dp</dimen> <dimen name="screenshot_offset_y">48dp</dimen> <dimen name="screenshot_offset_x">16dp</dimen> <dimen name="screenshot_dismiss_button_tappable_size">48dp</dimen> @@ -314,13 +314,13 @@ <dimen name="screenshot_action_container_corner_radius">10dp</dimen> <dimen name="screenshot_action_container_padding_vertical">10dp</dimen> <dimen name="screenshot_action_container_margin_horizontal">8dp</dimen> - <dimen name="screenshot_action_container_padding_left">100dp</dimen> + <dimen name="screenshot_action_container_padding_left">96dp</dimen> <dimen name="screenshot_action_container_padding_right">8dp</dimen> <!-- Radius of the chip background on global screenshot actions --> <dimen name="screenshot_button_corner_radius">20dp</dimen> - <dimen name="screenshot_action_chip_margin_horizontal">4dp</dimen> - <dimen name="screenshot_action_chip_padding_vertical">10dp</dimen> - <dimen name="screenshot_action_chip_icon_size">20dp</dimen> + <dimen name="screenshot_action_chip_margin_right">8dp</dimen> + <dimen name="screenshot_action_chip_padding_vertical">7dp</dimen> + <dimen name="screenshot_action_chip_icon_size">18dp</dimen> <dimen name="screenshot_action_chip_padding_start">8dp</dimen> <!-- Padding between icon and text --> <dimen name="screenshot_action_chip_padding_middle">8dp</dimen> @@ -1159,7 +1159,7 @@ <!-- Extra padding around the dismiss target for bubbles --> <dimen name="bubble_dismiss_slop">16dp</dimen> <!-- Height of button allowing users to adjust settings for bubbles. --> - <dimen name="bubble_settings_size">48dp</dimen> + <dimen name="bubble_manage_button_height">48dp</dimen> <!-- How far, horizontally, to animate the expanded view over when animating in/out. --> <dimen name="bubble_expanded_animate_x_distance">100dp</dimen> <!-- How far, vertically, to animate the expanded view over when animating in/out. --> @@ -1175,16 +1175,22 @@ <!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. --> <dimen name="bubble_stack_offscreen">9dp</dimen> <!-- How far down the screen the stack starts. --> - <dimen name="bubble_stack_starting_offset_y">96dp</dimen> + <dimen name="bubble_stack_starting_offset_y">120dp</dimen> <!-- Space between the pointer triangle and the bubble expanded view --> <dimen name="bubble_pointer_margin">8dp</dimen> - <!-- Height of the permission prompt shown with bubbles --> - <dimen name="bubble_permission_height">120dp</dimen> <!-- Padding applied to the bubble dismiss target. Touches in this padding cause the bubbles to snap to the dismiss target. --> <dimen name="bubble_dismiss_target_padding_x">40dp</dimen> <dimen name="bubble_dismiss_target_padding_y">20dp</dimen> + <!-- Bubbles user education views --> + <dimen name="bubbles_manage_education_width">160dp</dimen> + <!-- The inset from the top bound of the manage button to place the user education. --> + <dimen name="bubbles_manage_education_top_inset">10dp</dimen> + <!-- Size of padding for the user education cling, this should at minimum be larger than + individual_bubble_size + some padding. --> + <dimen name="bubble_stack_user_education_side_inset">72dp</dimen> + <!-- Size of the RAT type for CellularTile --> <dimen name="celltile_rat_type_size">10sp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 4aafec886a37..496ab439bdc0 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2586,6 +2586,12 @@ <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string> <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=20] --> <string name="bubble_dismiss_text">Dismiss</string> + <!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]--> + <string name="bubbles_user_education_title">Keep chats up front</string> + <!-- Descriptive text for the bubble feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=NONE] --> + <string name="bubbles_user_education_description">New chats from <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> will appear as bubbles. Tap a bubble to open it. Drag to move it.\n\nTap the bubble</string> + <!-- Text for the bubble "manage" button feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=80]--> + <string name="bubbles_user_education_manage">Tap Manage to turn off bubbles from this app</string> <!-- Notification content text when the system navigation mode changes as a result of changing the default launcher [CHAR LIMIT=NONE] --> <string name="notification_content_system_nav_changed">System navigation updated. To make changes, go to Settings.</string> @@ -2614,8 +2620,8 @@ <string name="controls_providers_subtitle">Choose an app from which to add controls</string> <!-- Number of favorites for controls management screen [CHAR LIMIT=NONE]--> <plurals name="controls_number_of_favorites"> - <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> current favorite.</item> - <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> current favorites.</item> + <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> control added.</item> + <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> controls added.</item> </plurals> <!-- Controls management controls screen default title [CHAR LIMIT=30] --> @@ -2626,6 +2632,10 @@ <string name="controls_favorite_header_favorites">Favorites</string> <!-- Controls management controls screen all header [CHAR LIMIT=50] --> <string name="controls_favorite_header_all">All</string> - <!-- Controls management controls screen error on load message [CHAR LIMIT=50] --> + <!-- Controls management controls screen error on load message [CHAR LIMIT=60] --> <string name="controls_favorite_load_error">The list of all controls could not be loaded.</string> + <!-- Controls management controls screen header for Other zone [CHAR LIMIT=60] --> + <string name="controls_favorite_other_zone_header">Other</string> + + </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 36c4526fb521..d9b1452b6bb1 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -514,7 +514,7 @@ <style name="TextAppearance.NotificationInfo.Button"> <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> <item name="android:textSize">14sp</item> - <item name="android:textColor">@color/notification_guts_info_button_color</item> + <item name="android:textColor">?android:attr/colorAccent</item> <item name="android:background">@drawable/btn_borderless_rect</item> <item name="android:gravity">center_vertical</item> <item name="android:focusable">true</item> @@ -550,7 +550,7 @@ <style name="TextAppearance.NotificationImportanceButton"> <item name="android:textSize">@dimen/notification_importance_button_text</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> - <item name="android:textColor">@color/notification_guts_priority_contents</item> + <item name="android:textColor">?android:attr/colorAccent</item> <item name="android:gravity">center</item> </style> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java index 4474a49e55b8..eca6ebf7f8e5 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java @@ -62,7 +62,9 @@ public class ThumbnailData { orientation = snapshot.getOrientation(); rotation = snapshot.getRotation(); reducedResolution = snapshot.isLowResolution(); - scale = snapshot.getScale(); + // TODO(b/149579527): Pass task size instead of computing scale. + // Assume width and height were scaled the same; compute scale only for width + scale = (float) thumbnail.getWidth() / snapshot.getTaskSize().x; isRealSnapshot = snapshot.isRealSnapshot(); isTranslucent = snapshot.isTranslucent(); windowingMode = snapshot.getWindowingMode(); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index a130092c77d1..49e3e5724988 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -370,8 +370,7 @@ public class ActivityManagerWrapper { Rect initialBounds) { try { return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId, - createMode, true /* onTop */, false /* animate */, initialBounds, - true /* showRecents */); + true /* onTop */); } catch (RemoteException e) { return false; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index 6cd6118ede6b..bbb83c73446c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -61,14 +61,6 @@ public class RecentsAnimationControllerCompat { } } - public void setSplitScreenMinimized(boolean minimized) { - try { - mAnimationController.setSplitScreenMinimized(minimized); - } catch (RemoteException e) { - Log.e(TAG, "Failed to set minimize dock", e); - } - } - public void hideCurrentInputMethod() { try { mAnimationController.hideCurrentInputMethod(); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index e28b1e2806e9..d64bf77ad9d5 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -191,18 +191,6 @@ public class WindowManagerWrapper { } /** - * Registers a docked stack listener with the system. - */ - public void registerDockedStackListener(DockedStackListenerCompat listener) { - try { - WindowManagerGlobal.getWindowManagerService().registerDockedStackListener( - listener.mListener); - } catch (RemoteException e) { - Log.w(TAG, "Failed to register docked stack listener"); - } - } - - /** * Adds a pinned stack listener, which will receive updates from the window manager service * along with any other pinned stack listeners that were added via this method. */ diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index ba8a1a945a77..3cf07d14cbf2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -19,7 +19,9 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.ViewRootImpl.sNewInsetsMode; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; + import static com.android.systemui.DejankUtils.whitelistIpcs; + import static java.lang.Integer.max; import android.app.Activity; @@ -28,7 +30,6 @@ import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; -import android.graphics.Rect; import android.metrics.LogMaker; import android.os.Handler; import android.os.Looper; @@ -511,6 +512,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe boolean finish = false; boolean strongAuth = false; int eventSubtype = -1; + mCurrentSecuritySelection = whitelistIpcs(() -> + mSecurityModel.getSecurityMode(targetUserId)); if (mUpdateMonitor.getUserHasTrust(targetUserId)) { finish = true; eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS; @@ -518,13 +521,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe finish = true; eventSubtype = BOUNCER_DISMISS_BIOMETRIC; } else if (SecurityMode.None == mCurrentSecuritySelection) { - SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId); - if (SecurityMode.None == securityMode) { - finish = true; // no security required - eventSubtype = BOUNCER_DISMISS_NONE_SECURITY; - } else { - showSecurityScreen(securityMode); // switch to the alternate security view - } + finish = true; // no security required + eventSubtype = BOUNCER_DISMISS_NONE_SECURITY; } else if (authenticated) { switch (mCurrentSecuritySelection) { case Pattern: diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index 924d16dd27d7..f01fa811c529 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -71,7 +71,8 @@ public class ForegroundServiceNotificationListener { public void onEntryRemoved( NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { removeNotification(entry.getSbn()); } }); diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 4473b010cbda..dbcdead8de9f 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -20,7 +20,9 @@ import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; +import android.os.Handler; import android.os.HandlerThread; +import android.os.SystemClock; import android.os.Trace; import android.service.wallpaper.WallpaperService; import android.util.Log; @@ -94,18 +96,28 @@ public class ImageWallpaper extends WallpaperService { private EglHelper mEglHelper; private StatusBarStateController mController; private final Runnable mFinishRenderingTask = this::finishRendering; - private final boolean mNeedTransition; private boolean mShouldStopTransition; - @VisibleForTesting - final boolean mIsHighEndGfx; - private final boolean mDisplayNeedsBlanking; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final Object mMonitor = new Object(); + @VisibleForTesting + boolean mIsHighEndGfx; + private boolean mDisplayNeedsBlanking; + private boolean mNeedTransition; private boolean mNeedRedraw; // This variable can only be accessed in synchronized block. private boolean mWaitingForRendering; GLEngine(Context context, DozeParameters dozeParameters) { + init(dozeParameters); + } + + @VisibleForTesting + GLEngine(DozeParameters dozeParameters, Handler handler) { + super(SystemClock::elapsedRealtime, handler); + init(dozeParameters); + } + + private void init(DozeParameters dozeParameters) { mIsHighEndGfx = ActivityManager.isHighEndGfx(); mDisplayNeedsBlanking = dozeParameters.getDisplayNeedsBlanking(); mNeedTransition = mIsHighEndGfx && !mDisplayNeedsBlanking; diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 10ae3434daaa..5e6589f76c13 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -57,7 +57,9 @@ public final class Prefs { Key.SEEN_RINGER_GUIDANCE_COUNT, Key.QS_HAS_TURNED_OFF_MOBILE_DATA, Key.TOUCHED_RINGER_TOGGLE, - Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP + Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, + Key.HAS_SEEN_BUBBLES_EDUCATION, + Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION }) public @interface Key { @Deprecated @@ -103,6 +105,8 @@ public final class Prefs { String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData"; String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle"; String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip"; + String HAS_SEEN_BUBBLES_EDUCATION = "HasSeenBubblesOnboarding"; + String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding"; } public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { @@ -164,7 +168,7 @@ public final class Prefs { get(context).unregisterOnSharedPreferenceChangeListener(listener); } - private static SharedPreferences get(Context context) { + public static SharedPreferences get(Context context) { return context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE); } } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 6ce6353147fb..0f896c44ae63 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -99,7 +99,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS; private DisplayManager mDisplayManager; - private boolean mIsRegistered; + @VisibleForTesting + protected boolean mIsRegistered; private final BroadcastDispatcher mBroadcastDispatcher; private final Handler mMainHandler; private final TunerService mTunerService; @@ -168,7 +169,6 @@ public class ScreenDecorations extends SystemUI implements Tunable { mDisplayManager = mContext.getSystemService(DisplayManager.class); updateRoundedCornerRadii(); setupDecorations(); - mDisplayListener = new DisplayManager.DisplayListener() { @Override public void onDisplayAdded(int displayId) { @@ -230,7 +230,10 @@ public class ScreenDecorations extends SystemUI implements Tunable { removeAllOverlays(); } - if (hasOverlays() && !mIsRegistered) { + if (hasOverlays()) { + if (mIsRegistered) { + return; + } DisplayMetrics metrics = new DisplayMetrics(); mDisplayManager.getDisplay(DEFAULT_DISPLAY).getMetrics(metrics); mDensity = metrics.density; @@ -271,7 +274,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { return mContext.getDisplay().getCutout(); } - private boolean hasOverlays() { + @VisibleForTesting + boolean hasOverlays() { if (mOverlays == null) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index a220dac0af41..48457f627e83 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -425,7 +425,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi public void onEntryRemoved( NotificationEntry entry, @android.annotation.Nullable NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { BubbleController.this.onEntryRemoved(entry); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java index 319066221600..e800011981a9 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java @@ -16,6 +16,9 @@ package com.android.systemui.bubbles; +import android.content.Context; +import android.provider.Settings; + import java.util.List; /** @@ -41,6 +44,20 @@ public class BubbleDebugConfig { static final boolean DEBUG_BUBBLE_EXPANDED_VIEW = false; static final boolean DEBUG_EXPERIMENTS = true; static final boolean DEBUG_OVERFLOW = false; + static final boolean DEBUG_USER_EDUCATION = false; + + private static final boolean FORCE_SHOW_USER_EDUCATION = false; + private static final String FORCE_SHOW_USER_EDUCATION_SETTING = + "force_show_bubbles_user_education"; + + /** + * @return whether we should force show user education for bubbles. Used for debugging & demos. + */ + static boolean forceShowUserEducation(Context context) { + boolean forceShow = Settings.Secure.getInt(context.getContentResolver(), + FORCE_SHOW_USER_EDUCATION_SETTING, 0) != 0; + return FORCE_SHOW_USER_EDUCATION || forceShow; + } static String formatBubblesString(List<Bubble> bubbles, Bubble selected) { StringBuilder sb = new StringBuilder(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index e3983c5b2d92..a6f759f3e0b9 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -243,7 +243,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList mPointerView.setVisibility(INVISIBLE); mSettingsIconHeight = getContext().getResources().getDimensionPixelSize( - R.dimen.bubble_settings_size); + R.dimen.bubble_manage_button_height); mSettingsIcon = findViewById(R.id.settings_button); mSettingsIcon.setOnClickListener(this); @@ -531,6 +531,16 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList } /** + * Position of the manage button displayed in the expanded view. Used for placing user + * education about the manage button. + */ + public Rect getManageButtonLocationOnScreen() { + mTempLoc = mSettingsIcon.getLocationOnScreen(); + return new Rect(mTempLoc[0], mTempLoc[1], mTempLoc[0] + mSettingsIcon.getWidth(), + mTempLoc[1] + mSettingsIcon.getHeight()); + } + + /** * Removes and releases an ActivityView if one was previously created for this bubble. */ public void cleanUpExpandedState() { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java index 20b3386b450d..2873811aeffb 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java @@ -73,9 +73,6 @@ public class BubbleExperimentConfig { private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps"; - private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow"; - private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = false; - /** * When true, if a notification has the information necessary to bubble (i.e. valid * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata} @@ -131,16 +128,6 @@ public class BubbleExperimentConfig { } /** - * When true, show a menu when a bubble is long-pressed, which will allow the user to take - * actions on that bubble. - */ - static boolean allowBubbleOverflow(Context context) { - return Settings.Secure.getInt(context.getContentResolver(), - ALLOW_BUBBLE_OVERFLOW, - ALLOW_BUBBLE_OVERFLOW_DEFAULT ? 1 : 0) != 0; - } - - /** * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as * the notification has necessary info for BubbleMetadata. diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java new file mode 100644 index 000000000000..f4d64322c7ff --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java @@ -0,0 +1,109 @@ +/* + * 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.systemui.bubbles; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.ShapeDrawable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.internal.util.ContrastColorUtil; +import com.android.systemui.R; +import com.android.systemui.recents.TriangleShape; + +/** + * Educational view to highlight the manage button that allows a user to configure the settings + * for the bubble. Shown only the first time a user expands a bubble. + */ +public class BubbleManageEducationView extends LinearLayout { + + private View mPointerView; + private View mManageView; + + public BubbleManageEducationView(Context context) { + this(context, null); + } + + public BubbleManageEducationView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BubbleManageEducationView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public BubbleManageEducationView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mManageView = findViewById(R.id.manage_education_view); + + final TypedArray ta = mContext.obtainStyledAttributes( + new int[] {android.R.attr.colorAccent, + android.R.attr.textColorPrimaryInverse}); + final int bgColor = ta.getColor(0, Color.BLACK); + int textColor = ta.getColor(1, Color.WHITE); + ta.recycle(); + + textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true); + ((TextView) findViewById(R.id.user_education_description)).setTextColor(textColor); + + final Resources res = getResources(); + final int pointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width); + final int pointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); + + ShapeDrawable triangleShape = + new ShapeDrawable(TriangleShape.create( + pointerWidth, pointerHeight, false /* isPointingUp */)); + triangleShape.setTint(bgColor); + + mPointerView = findViewById(R.id.user_education_pointer); + mPointerView.setBackground(triangleShape); + } + + /** + * Specifies the x value this pointer should point to. + */ + public void setPointerPosition(int x) { + mPointerView.setTranslationX(x - (mPointerView.getWidth() / 2)); + } + + /** + * Specifies the position for the manage view. + */ + public void setManageViewPosition(int x, int y) { + mManageView.setTranslationX(x); + mManageView.setTranslationY(y); + } + + /** + * @return the height of the view that shows the educational text and pointer. + */ + public int getManageViewHeight() { + return mManageView.getHeight(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java index a0e744979112..313bb4250570 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java @@ -62,11 +62,12 @@ public class BubbleOverflow implements BubbleViewProvider { R.dimen.bubble_overflow_icon_bitmap_size); } - public void setUpOverflow(ViewGroup parentViewGroup) { + void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) { mOverflowExpandedView = (BubbleExpandedView) mInflater.inflate( R.layout.bubble_expanded_view, parentViewGroup /* root */, false /* attachToRoot */); mOverflowExpandedView.setOverflow(true); + mOverflowExpandedView.setStackView(stackView); updateIcon(mContext, parentViewGroup); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 072c20c684dd..6647069f2033 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -19,9 +19,13 @@ package com.android.systemui.bubbles; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN; +import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_EDUCATION; +import static com.android.systemui.Prefs.Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION; import static com.android.systemui.bubbles.BadgedImageView.DOT_STATE_DEFAULT; import static com.android.systemui.bubbles.BadgedImageView.DOT_STATE_SUPPRESSED_FOR_FLYOUT; import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW; +import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; @@ -33,6 +37,8 @@ import android.app.Notification; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; @@ -57,6 +63,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.FrameLayout; +import android.widget.TextView; import androidx.annotation.MainThread; import androidx.annotation.Nullable; @@ -66,7 +73,9 @@ import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ContrastColorUtil; import com.android.internal.widget.ViewClippingUtil; +import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.bubbles.animation.ExpandedAnimationController; import com.android.systemui.bubbles.animation.PhysicsAnimationLayout; @@ -88,6 +97,10 @@ import java.util.List; public class BubbleStackView extends FrameLayout { private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES; + /** Animation durations for bubble stack user education views. **/ + private static final int ANIMATE_STACK_USER_EDUCATION_DURATION = 200; + private static final int ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT = 40; + /** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */ static final float FLYOUT_DRAG_PERCENT_DISMISS = 0.25f; @@ -171,6 +184,12 @@ public class BubbleStackView extends FrameLayout { * previous one animates out. */ private Runnable mAfterFlyoutHidden; + /** + * Set when the flyout is tapped, so that we can expand the bubble associated with the flyout + * once it collapses. + */ + @Nullable + private Bubble mBubbleToExpandAfterFlyoutCollapse = null; /** Layout change listener that moves the stack to the nearest valid position on rotation. */ private OnLayoutChangeListener mOrientationChangedListener; @@ -319,6 +338,14 @@ public class BubbleStackView extends FrameLayout { private BubbleOverflow mBubbleOverflow; + private boolean mShouldShowUserEducation; + private boolean mAnimatingEducationAway; + private View mUserEducationView; + + private boolean mShouldShowManageEducation; + private BubbleManageEducationView mManageEducationView; + private boolean mAnimatingManageEducationAway; + public BubbleStackView(Context context, BubbleData data, @Nullable SurfaceSynchronizer synchronizer, FloatingContentCoordinator floatingContentCoordinator) { @@ -361,6 +388,8 @@ public class BubbleStackView extends FrameLayout { mDisplaySize, mExpandedViewPadding, res.getConfiguration().orientation); mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER; + setUpUserEducation(); + mBubbleContainer = new PhysicsAnimationLayout(context); mBubbleContainer.setActiveController(mStackAnimationController); mBubbleContainer.setElevation(elevation); @@ -500,10 +529,50 @@ public class BubbleStackView extends FrameLayout { }); } - void showExpandedViewContents(int displayId) { - if (mExpandedBubble != null - && mExpandedBubble.getExpandedView().getVirtualDisplayId() == displayId) { - mExpandedBubble.setContentVisibility(true); + private void setUpUserEducation() { + if (mUserEducationView != null) { + removeView(mUserEducationView); + } + mShouldShowUserEducation = shouldShowBubblesEducation(); + if (DEBUG_USER_EDUCATION) { + Log.d(TAG, "shouldShowUserEducation: " + mShouldShowUserEducation); + } + if (mShouldShowUserEducation) { + mUserEducationView = mInflater.inflate(R.layout.bubble_stack_user_education, this, + false /* attachToRoot */); + mUserEducationView.setVisibility(GONE); + + final TypedArray ta = mContext.obtainStyledAttributes( + new int[] {android.R.attr.colorAccent, + android.R.attr.textColorPrimaryInverse}); + final int bgColor = ta.getColor(0, Color.BLACK); + int textColor = ta.getColor(1, Color.WHITE); + ta.recycle(); + textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true); + + TextView title = mUserEducationView.findViewById(R.id.user_education_title); + TextView description = mUserEducationView.findViewById(R.id.user_education_description); + title.setTextColor(textColor); + description.setTextColor(textColor); + + addView(mUserEducationView); + } + + if (mManageEducationView != null) { + removeView(mManageEducationView); + } + mShouldShowManageEducation = shouldShowManageEducation(); + if (DEBUG_USER_EDUCATION) { + Log.d(TAG, "shouldShowManageEducation: " + mShouldShowManageEducation); + } + if (mShouldShowManageEducation) { + mManageEducationView = (BubbleManageEducationView) + mInflater.inflate(R.layout.bubbles_manage_button_education, this, + false /* attachToRoot */); + mManageEducationView.setVisibility(GONE); + mManageEducationView.setElevation(mBubbleElevation); + + addView(mManageEducationView); } } @@ -520,13 +589,10 @@ public class BubbleStackView extends FrameLayout { } private void setUpOverflow() { - if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) { - return; - } int overflowBtnIndex = 0; if (mBubbleOverflow == null) { - mBubbleOverflow = new BubbleOverflow(mContext); - mBubbleOverflow.setUpOverflow(this); + mBubbleOverflow = new BubbleOverflow(getContext()); + mBubbleOverflow.setUpOverflow(mBubbleContainer, this); } else { mBubbleContainer.removeView(mBubbleOverflow.getBtn()); mBubbleOverflow.updateIcon(mContext, this); @@ -542,6 +608,7 @@ public class BubbleStackView extends FrameLayout { public void onThemeChanged() { setUpFlyout(); setUpOverflow(); + setUpUserEducation(); } /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */ @@ -733,9 +800,8 @@ public class BubbleStackView extends FrameLayout { @Nullable Bubble getExpandedBubble() { if (mExpandedBubble == null - || (BubbleExperimentConfig.allowBubbleOverflow(mContext) - && mExpandedBubble.getIconView() == mBubbleOverflow.getBtn() - && mExpandedBubble.getKey() == BubbleOverflow.KEY)) { + || (mExpandedBubble.getIconView() == mBubbleOverflow.getBtn() + && BubbleOverflow.KEY.equals(mExpandedBubble.getKey()))) { return null; } return (Bubble) mExpandedBubble; @@ -747,6 +813,12 @@ public class BubbleStackView extends FrameLayout { Log.d(TAG, "addBubble: " + bubble); } + if (getBubbleCount() == 0 && mShouldShowUserEducation) { + // Override the default stack position if we're showing user education. + mStackAnimationController.setStackPosition( + mStackAnimationController.getDefaultStartPosition()); + } + if (getBubbleCount() == 0) { mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide(); } @@ -785,9 +857,6 @@ public class BubbleStackView extends FrameLayout { } private void updateOverflowBtnVisibility(boolean apply) { - if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) { - return; - } if (mIsExpanded) { if (DEBUG_BUBBLE_STACK_VIEW) { Log.d(TAG, "Show overflow button."); @@ -888,6 +957,109 @@ public class BubbleStackView extends FrameLayout { } /** + * If necessary, shows the user education view for the bubble stack. This appears the first + * time a user taps on a bubble. + * + * @return true if user education was shown, false otherwise. + */ + private boolean maybeShowStackUserEducation() { + if (mShouldShowUserEducation && mUserEducationView.getVisibility() != VISIBLE) { + Bubble b = mBubbleData.getSelectedBubble(); + TextView description = mUserEducationView.findViewById(R.id.user_education_description); + description.setText(mContext.getString( + R.string.bubbles_user_education_description, b.getAppName())); + + mUserEducationView.setAlpha(0); + mUserEducationView.setVisibility(VISIBLE); + // Post so we have height of mUserEducationView + mUserEducationView.post(() -> { + final int viewHeight = mUserEducationView.getHeight(); + PointF stackPosition = mStackAnimationController.getDefaultStartPosition(); + final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2); + mUserEducationView.setTranslationY(translationY); + mUserEducationView.animate() + .setDuration(ANIMATE_STACK_USER_EDUCATION_DURATION) + .setInterpolator(FAST_OUT_SLOW_IN) + .alpha(1); + }); + Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, true); + return true; + } + return false; + } + + /** + * If necessary, hides the user education view for the bubble stack. + * + * @param fromExpansion if true this indicates the hide is happening due to the bubble being + * expanded, false if due to a touch outside of the bubble stack. + */ + void hideStackUserEducation(boolean fromExpansion) { + if (mShouldShowUserEducation + && mUserEducationView.getVisibility() == VISIBLE + && !mAnimatingEducationAway) { + mAnimatingEducationAway = true; + mUserEducationView.animate() + .alpha(0) + .setDuration(fromExpansion + ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT + : ANIMATE_STACK_USER_EDUCATION_DURATION) + .withEndAction(() -> { + mAnimatingEducationAway = false; + mShouldShowUserEducation = shouldShowBubblesEducation(); + mUserEducationView.setVisibility(GONE); + }); + } + } + + /** + * If necessary, toggles the user education view for the manage button. This is shown when the + * bubble stack is expanded for the first time. + * + * @param show whether the user education view should show or not. + */ + void maybeShowManageEducation(boolean show) { + if (mManageEducationView == null) { + return; + } + if (show + && mShouldShowManageEducation + && mManageEducationView.getVisibility() != VISIBLE + && mIsExpanded) { + mManageEducationView.setAlpha(0); + mManageEducationView.setVisibility(VISIBLE); + mManageEducationView.post(() -> { + final Rect position = + mExpandedBubble.getExpandedView().getManageButtonLocationOnScreen(); + final int viewHeight = mManageEducationView.getManageViewHeight(); + final int inset = getResources().getDimensionPixelSize( + R.dimen.bubbles_manage_education_top_inset); + mManageEducationView.bringToFront(); + mManageEducationView.setManageViewPosition(position.left, + position.top - viewHeight + inset); + mManageEducationView.setPointerPosition(position.centerX() - position.left); + mManageEducationView.animate() + .setDuration(ANIMATE_STACK_USER_EDUCATION_DURATION) + .setInterpolator(FAST_OUT_SLOW_IN).alpha(1); + }); + Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, true); + } else if (!show + && mManageEducationView.getVisibility() == VISIBLE + && !mAnimatingManageEducationAway) { + mManageEducationView.animate() + .alpha(0) + .setDuration(mIsExpansionAnimating + ? ANIMATE_STACK_USER_EDUCATION_DURATION_SHORT + : ANIMATE_STACK_USER_EDUCATION_DURATION) + .withEndAction(() -> { + mAnimatingManageEducationAway = false; + mShouldShowManageEducation = shouldShowManageEducation(); + mManageEducationView.setVisibility(GONE); + }); + } + } + + /** * Dismiss the stack of bubbles. * * @deprecated @@ -911,8 +1083,7 @@ public class BubbleStackView extends FrameLayout { float y = event.getRawY(); if (mIsExpanded) { if (isIntersecting(mBubbleContainer, x, y)) { - if (BubbleExperimentConfig.allowBubbleOverflow(mContext) - && isIntersecting(mBubbleOverflow.getBtn(), x, y)) { + if (isIntersecting(mBubbleOverflow.getBtn(), x, y)) { return mBubbleOverflow.getBtn(); } // Could be tapping or dragging a bubble while expanded @@ -931,7 +1102,17 @@ public class BubbleStackView extends FrameLayout { return null; } else if (mFlyout.getVisibility() == VISIBLE && isIntersecting(mFlyout, x, y)) { return mFlyout; + } else if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) { + View bubbleChild = mBubbleContainer.getChildAt(0); + if (isIntersecting(bubbleChild, x, y)) { + return this; + } else if (isIntersecting(mUserEducationView, x, y)) { + return mUserEducationView; + } else { + return null; + } } + // If it wasn't an individual bubble in the expanded state, or the flyout, it's the stack. return this; } @@ -941,22 +1122,6 @@ public class BubbleStackView extends FrameLayout { } /** - * Collapses the stack of bubbles. - * <p> - * Must be called from the main thread. - * - * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)} - */ - @Deprecated - @MainThread - void collapseStack() { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "collapseStack()"); - } - mBubbleData.setExpanded(false); - } - - /** * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)} */ @Deprecated @@ -965,25 +1130,16 @@ public class BubbleStackView extends FrameLayout { if (DEBUG_BUBBLE_STACK_VIEW) { Log.d(TAG, "collapseStack(endRunnable)"); } - collapseStack(); + mBubbleData.setExpanded(false); // TODO - use the runnable at end of animation endRunnable.run(); } - /** - * Expands the stack of bubbles. - * <p> - * Must be called from the main thread. - * - * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)} - */ - @Deprecated - @MainThread - void expandStack() { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "expandStack()"); + void showExpandedViewContents(int displayId) { + if (mExpandedBubble != null + && mExpandedBubble.getExpandedView().getVirtualDisplayId() == displayId) { + mExpandedBubble.setContentVisibility(true); } - mBubbleData.setExpanded(true); } private void beforeExpandedViewAnimation() { @@ -1003,11 +1159,12 @@ public class BubbleStackView extends FrameLayout { mIsExpanded = false; final BubbleViewProvider previouslySelected = mExpandedBubble; beforeExpandedViewAnimation(); + maybeShowManageEducation(false); if (DEBUG_BUBBLE_STACK_VIEW) { Log.d(TAG, "animateCollapse"); - Log.d(TAG, BubbleDebugConfig.formatBubblesString(this.getBubblesOnScreen(), - this.getExpandedBubble())); + Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(), + getExpandedBubble())); } updateOverflowBtnVisibility(/* apply */ false); mBubbleContainer.cancelAllAnimations(); @@ -1029,6 +1186,7 @@ public class BubbleStackView extends FrameLayout { private void animateExpansion() { mIsExpanded = true; + hideStackUserEducation(true /* fromExpansion */); beforeExpandedViewAnimation(); mBubbleContainer.setActiveController(mExpandedAnimationController); @@ -1036,6 +1194,7 @@ public class BubbleStackView extends FrameLayout { mExpandedAnimationController.expandFromStack(() -> { updatePointerPosition(); afterExpandedViewAnimation(); + maybeShowManageEducation(true); } /* after */); mExpandedViewContainer.setTranslationX(getCollapsedX()); @@ -1082,11 +1241,19 @@ public class BubbleStackView extends FrameLayout { } } + /** Called when the collapsed stack is tapped on. */ + void onStackTapped() { + if (!maybeShowStackUserEducation()) { + mBubbleData.setExpanded(true); + } + } + /** Called when a drag operation on an individual bubble has started. */ public void onBubbleDragStart(View bubble) { if (DEBUG_BUBBLE_STACK_VIEW) { Log.d(TAG, "onBubbleDragStart: bubble=" + bubble); } + maybeShowManageEducation(false); mExpandedAnimationController.prepareForBubbleDrag(bubble); } @@ -1137,6 +1304,7 @@ public class BubbleStackView extends FrameLayout { return; } + hideStackUserEducation(false /* fromExpansion */); springInDismissTarget(); mStackAnimationController.moveStackFromTouch(x, y); } @@ -1199,14 +1367,13 @@ public class BubbleStackView extends FrameLayout { mFlyout.setTranslationX(mFlyout.getRestingTranslationX() + overscrollTranslation); } - /** - * Set when the flyout is tapped, so that we can expand the bubble associated with the flyout - * once it collapses. - */ - @Nullable private Bubble mBubbleToExpandAfterFlyoutCollapse = null; - void onFlyoutTapped() { - mBubbleToExpandAfterFlyoutCollapse = mBubbleData.getSelectedBubble(); + if (maybeShowStackUserEducation()) { + // If we're showing user education, don't open the bubble show the education first + mBubbleToExpandAfterFlyoutCollapse = null; + } else { + mBubbleToExpandAfterFlyoutCollapse = mBubbleData.getSelectedBubble(); + } mFlyout.removeCallbacks(mHideFlyout); mHideFlyout.run(); @@ -1229,6 +1396,8 @@ public class BubbleStackView extends FrameLayout { mFlyout.removeCallbacks(mHideFlyout); animateFlyoutCollapsed(shouldDismiss, velX); + + maybeShowStackUserEducation(); } /** @@ -1440,6 +1609,7 @@ public class BubbleStackView extends FrameLayout { if (flyoutMessage == null || flyoutMessage.message == null || !bubble.showFlyout() + || (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) || isExpanded() || mIsExpansionAnimating || mIsGestureInProgress @@ -1525,7 +1695,12 @@ public class BubbleStackView extends FrameLayout { @Override public void getBoundsOnScreen(Rect outRect) { - // If the bubble menu is open, the entire screen should capture touch events. + if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) { + // When user education shows then capture all touches + outRect.set(0, 0, getWidth(), getHeight()); + return; + } + if (!mIsExpanded) { if (getBubbleCount() > 0) { mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect); @@ -1645,11 +1820,8 @@ public class BubbleStackView extends FrameLayout { * @return the number of bubbles in the stack view. */ public int getBubbleCount() { - if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) { - // Subtract 1 for the overflow button which is always in the bubble container. - return mBubbleContainer.getChildCount() - 1; - } - return mBubbleContainer.getChildCount(); + // Subtract 1 for the overflow button that is always in the bubble container. + return mBubbleContainer.getChildCount() - 1; } /** @@ -1715,6 +1887,18 @@ public class BubbleStackView extends FrameLayout { return mExpandedBubble.getExpandedView().performBackPressIfNeeded(); } + /** Whether the educational view should appear for bubbles. **/ + private boolean shouldShowBubblesEducation() { + return BubbleDebugConfig.forceShowUserEducation(getContext()) + || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_EDUCATION, false); + } + + /** Whether the educational view should appear for the expanded view "manage" button. **/ + private boolean shouldShowManageEducation() { + return BubbleDebugConfig.forceShowUserEducation(getContext()) + || !Prefs.getBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, false); + } + /** For debugging only */ List<Bubble> getBubblesOnScreen() { List<Bubble> bubbles = new ArrayList<>(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java index 5e3e747ad2c0..46d1e0dfbab7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java @@ -24,7 +24,6 @@ import android.view.View; import android.view.ViewConfiguration; import com.android.systemui.Dependency; -import com.android.systemui.R; /** * Handles interpreting touches on a {@link BubbleStackView}. This includes expanding, collapsing, @@ -92,6 +91,7 @@ class BubbleTouchHandler implements View.OnTouchListener { // anything, collapse the stack. if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) { mBubbleData.setExpanded(false); + mStack.hideStackUserEducation(false /* fromExpansion */); resetForNextGesture(); return false; } @@ -102,6 +102,7 @@ class BubbleTouchHandler implements View.OnTouchListener { // Not touching anything touchable, but we shouldn't collapse (e.g. touching edge // of expanded view). + mStack.maybeShowManageEducation(false); resetForNextGesture(); return false; } @@ -217,9 +218,8 @@ class BubbleTouchHandler implements View.OnTouchListener { } } else if (mTouchedView == mStack.getExpandedBubbleView()) { mBubbleData.setExpanded(false); - } else if (isStack || isFlyout) { - // Toggle expansion - mBubbleData.setExpanded(!mBubbleData.isExpanded()); + } else if (isStack) { + mStack.onStackTapped(); } else { final String key = ((BadgedImageView) mTouchedView).getKey(); if (key == BubbleOverflow.KEY) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index 245d4afbf015..f22c8faad95c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -879,9 +879,10 @@ public class StackAnimationController extends } /** Moves the stack to a position instantly, with no animation. */ - private void setStackPosition(PointF pos) { + public void setStackPosition(PointF pos) { Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y)); mStackPosition.set(pos.x, pos.y); + mRestingStackPosition = mStackPosition; // If we're not the active controller, we don't want to physically move the bubble views. if (isActiveController()) { @@ -902,10 +903,10 @@ public class StackAnimationController extends } } - /** Returns the default stack position, which is on the top right. */ - private PointF getDefaultStartPosition() { + /** Returns the default stack position, which is on the top left. */ + public PointF getDefaultStartPosition() { return new PointF( - getAllowableStackPositionRegion().right, + getAllowableStackPositionRegion().left, getAllowableStackPositionRegion().top + mStackStartingVerticalOffset); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java index f719cc65be71..37c7a2e3027f 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java @@ -16,6 +16,7 @@ package com.android.systemui.classifier; +import android.app.ActivityManager; import android.content.Context; import android.database.ContentObserver; import android.hardware.Sensor; @@ -296,6 +297,10 @@ public class FalsingManagerImpl implements FalsingManager { mHandler.postDelayed(mPendingWtf, 1000); } } + if (ActivityManager.isRunningInUserTestHarness()) { + // This is a test device running UiAutomator code. + return false; + } if (mAccessibilityManager.isTouchExplorationEnabled()) { // Touch exploration triggers false positives in the classifier and // already sufficiently prevents false unlocks. diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java index 0ac1c1215a28..79b691bb3e37 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java @@ -39,6 +39,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingPlugin; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.ProximitySensor; @@ -69,6 +70,7 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { private final DockManager mDockManager; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private Executor mUiBgExecutor; + private final StatusBarStateController mStatusBarStateController; @Inject FalsingManagerProxy(Context context, PluginManager pluginManager, @Main Executor executor, @@ -76,12 +78,14 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { DeviceConfigProxy deviceConfig, DockManager dockManager, KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager, - @UiBackground Executor uiBgExecutor) { + @UiBackground Executor uiBgExecutor, + StatusBarStateController statusBarStateController) { mDisplayMetrics = displayMetrics; mProximitySensor = proximitySensor; mDockManager = dockManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mUiBgExecutor = uiBgExecutor; + mStatusBarStateController = statusBarStateController; mProximitySensor.setTag(PROXIMITY_SENSOR_TAG); mProximitySensor.setSensorDelay(SensorManager.SENSOR_DELAY_GAME); mDeviceConfig = deviceConfig; @@ -143,7 +147,8 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable { mKeyguardUpdateMonitor, mProximitySensor, mDeviceConfig, - mDockManager + mDockManager, + mStatusBarStateController ); } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java index a084ae6ed50f..caab18712b0b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java @@ -19,6 +19,7 @@ package com.android.systemui.classifier.brightline; import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_REMAIN_LOCKED; import static com.android.systemui.classifier.FalsingManagerImpl.FALSING_SUCCESS; +import android.app.ActivityManager; import android.hardware.biometrics.BiometricSourceType; import android.net.Uri; import android.os.Build; @@ -32,6 +33,8 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.classifier.Classifier; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.sensors.ProximitySensor; @@ -59,6 +62,7 @@ public class BrightLineFalsingManager implements FalsingManager { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final ProximitySensor mProximitySensor; private final DockManager mDockManager; + private final StatusBarStateController mStatusBarStateController; private boolean mSessionStarted; private MetricsLogger mMetricsLogger; private int mIsFalseTouchCalls; @@ -88,15 +92,29 @@ public class BrightLineFalsingManager implements FalsingManager { }; private boolean mPreviousResult = false; + private StatusBarStateController.StateListener mStatusBarStateListener = + new StatusBarStateController.StateListener() { + @Override + public void onStateChanged(int newState) { + logDebug("StatusBarState=" + StatusBarState.toShortString(newState)); + mState = newState; + updateSessionActive(); + } + }; + private int mState; + public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider, KeyguardUpdateMonitor keyguardUpdateMonitor, ProximitySensor proximitySensor, DeviceConfigProxy deviceConfigProxy, - DockManager dockManager) { + DockManager dockManager, StatusBarStateController statusBarStateController) { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mDataProvider = falsingDataProvider; mProximitySensor = proximitySensor; mDockManager = dockManager; + mStatusBarStateController = statusBarStateController; mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); + mStatusBarStateController.addCallback(mStatusBarStateListener); + mState = mStatusBarStateController.getState(); mMetricsLogger = new MetricsLogger(); mClassifiers = new ArrayList<>(); @@ -116,13 +134,12 @@ public class BrightLineFalsingManager implements FalsingManager { mProximitySensor.register(mSensorEventListener); } - private void unregisterSensors() { mProximitySensor.unregister(mSensorEventListener); } private void sessionStart() { - if (!mSessionStarted && !mShowingAod && mScreenOn) { + if (!mSessionStarted && shouldSessionBeActive()) { logDebug("Starting Session"); mSessionStarted = true; mJustUnlockedWithFace = false; @@ -145,6 +162,19 @@ public class BrightLineFalsingManager implements FalsingManager { } } + + private void updateSessionActive() { + if (shouldSessionBeActive()) { + sessionStart(); + } else { + sessionEnd(); + } + } + + private boolean shouldSessionBeActive() { + return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod; + } + private void updateInteractionType(@Classifier.InteractionType int type) { logDebug("InteractionType: " + type); mDataProvider.setInteractionType(type); @@ -161,8 +191,8 @@ public class BrightLineFalsingManager implements FalsingManager { return mPreviousResult; } - mPreviousResult = !mJustUnlockedWithFace && !mDockManager.isDocked() - && mClassifiers.stream().anyMatch(falsingClassifier -> { + mPreviousResult = !ActivityManager.isRunningInUserTestHarness() && !mJustUnlockedWithFace + && !mDockManager.isDocked() && mClassifiers.stream().anyMatch(falsingClassifier -> { boolean result = falsingClassifier.isFalseTouch(); if (result) { logInfo(String.format( @@ -232,11 +262,7 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void setShowingAod(boolean showingAod) { mShowingAod = showingAod; - if (showingAod) { - sessionEnd(); - } else { - sessionStart(); - } + updateSessionActive(); } @Override @@ -343,13 +369,13 @@ public class BrightLineFalsingManager implements FalsingManager { @Override public void onScreenTurningOn() { mScreenOn = true; - sessionStart(); + updateSessionActive(); } @Override public void onScreenOff() { mScreenOn = false; - sessionEnd(); + updateSessionActive(); } @@ -421,6 +447,7 @@ public class BrightLineFalsingManager implements FalsingManager { public void cleanup() { unregisterSensors(); mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); + mStatusBarStateController.removeCallback(mStatusBarStateListener); } static void logDebug(String msg) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt index 6ff1bbce672f..a67f6bd88ad8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.controller +import android.app.ActivityManager import android.content.ComponentName import android.content.Context import android.os.IBinder @@ -50,7 +51,7 @@ open class ControlsBindingControllerImpl @Inject constructor( private val refreshing = AtomicBoolean(false) - private var currentUser = context.user + private var currentUser = UserHandle.of(ActivityManager.getCurrentUser()) override val currentUserId: Int get() = currentUser.identifier diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index a2a08502a58f..3b06ebef9443 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.controller +import android.app.ActivityManager import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.ComponentName @@ -67,6 +68,7 @@ class ControlsControllerImpl @Inject constructor ( internal const val CONTROLS_AVAILABLE = "systemui.controls_available" internal val URI = Settings.Secure.getUriFor(CONTROLS_AVAILABLE) private const val USER_CHANGE_RETRY_DELAY = 500L // ms + private const val DEFAULT_ENABLED = 1 } // Map of map: ComponentName -> (String -> ControlInfo). @@ -77,15 +79,16 @@ class ControlsControllerImpl @Inject constructor ( private var userChanging: Boolean = true + private var currentUser = UserHandle.of(ActivityManager.getCurrentUser()) + override val currentUserId + get() = currentUser.identifier + private val contentResolver: ContentResolver get() = context.contentResolver - override var available = Settings.Secure.getInt(contentResolver, CONTROLS_AVAILABLE, 0) != 0 + override var available = Settings.Secure.getIntForUser( + contentResolver, CONTROLS_AVAILABLE, DEFAULT_ENABLED, currentUserId) != 0 private set - private var currentUser = context.user - override val currentUserId - get() = currentUser.identifier - private val persistenceWrapper = optionalWrapper.orElseGet { ControlsFavoritePersistenceWrapper( Environment.buildPath( @@ -104,7 +107,7 @@ class ControlsControllerImpl @Inject constructor ( userContext.filesDir, ControlsFavoritePersistenceWrapper.FILE_NAME) persistenceWrapper.changeFile(fileName) available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE, - /* default */ 0, newUser.identifier) != 0 + DEFAULT_ENABLED, newUser.identifier) != 0 synchronized(currentFavorites) { currentFavorites.clear() } @@ -140,7 +143,7 @@ class ControlsControllerImpl @Inject constructor ( return } available = Settings.Secure.getIntForUser(contentResolver, CONTROLS_AVAILABLE, - /* default */ 0, currentUserId) != 0 + DEFAULT_ENABLED, currentUserId) != 0 synchronized(currentFavorites) { currentFavorites.clear() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt new file mode 100644 index 000000000000..c05351795aed --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.management + +import android.text.TextUtils +import android.util.ArrayMap +import com.android.systemui.controls.ControlStatus +import com.android.systemui.controls.controller.ControlInfo + +/** + * This model is used to show all controls separated by zones. + * + * The model will sort the controls and zones in the following manner: + * * The zones will be sorted in a first seen basis + * * The controls in each zone will be sorted in a first seen basis. + * + * @property controls List of all controls as returned by loading + * @property initialFavoriteIds sorted ids of favorite controls + * @property noZoneString text to use as header for all controls that have blank or `null` zone. + */ +class AllModel( + private val controls: List<ControlStatus>, + initialFavoriteIds: List<String>, + private val emptyZoneString: CharSequence +) : ControlsModel { + + override val favorites: List<ControlInfo.Builder> + get() = favoriteIds.mapNotNull { id -> + val control = controls.firstOrNull { it.control.controlId == id }?.control + control?.let { + ControlInfo.Builder().apply { + controlId = it.controlId + controlTitle = it.title + deviceType = it.deviceType + } + } + } + + private val favoriteIds = initialFavoriteIds.toMutableList() + + override val elements: List<ElementWrapper> = createWrappers(controls) + + override fun changeFavoriteStatus(controlId: String, favorite: Boolean) { + if (favorite) { + favoriteIds.add(controlId) + } else { + favoriteIds.remove(controlId) + } + } + + private fun createWrappers(list: List<ControlStatus>): List<ElementWrapper> { + val map = list.groupByTo(OrderedMap(ArrayMap<CharSequence, MutableList<ControlStatus>>())) { + it.control.zone ?: "" + } + val output = mutableListOf<ElementWrapper>() + var emptyZoneValues: Sequence<ControlWrapper>? = null + for (zoneName in map.orderedKeys) { + val values = map.getValue(zoneName).asSequence().map { ControlWrapper(it) } + if (TextUtils.isEmpty(zoneName)) { + emptyZoneValues = values + } else { + output.add(ZoneNameWrapper(zoneName)) + output.addAll(values) + } + } + // Add controls with empty zone at the end + if (emptyZoneValues != null) { + if (map.size != 1) { + output.add(ZoneNameWrapper(emptyZoneString)) + } + output.addAll(emptyZoneValues) + } + return output + } + + private class OrderedMap<K, V>(private val map: MutableMap<K, V>) : MutableMap<K, V> by map { + + val orderedKeys = mutableListOf<K>() + + override fun put(key: K, value: V): V? { + if (key !in map) { + orderedKeys.add(key) + } + return map.put(key, value) + } + + override fun clear() { + orderedKeys.clear() + map.clear() + } + + override fun remove(key: K): V? { + val removed = map.remove(key) + if (removed != null) { + orderedKeys.remove(key) + } + return removed + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt index ac5e0893b526..25ebc65357ee 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt @@ -116,6 +116,10 @@ class FavoritesRenderer( fun renderFavoritesForComponent(component: ComponentName): String { val qty = favoriteFunction(component) - return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty) + if (qty != 0) { + return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty) + } else { + return "" + } } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt index d3cabe67790e..0870a4d179c9 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt @@ -42,8 +42,7 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit * @param onlyFavorites set to true to only display favorites instead of all controls */ class ControlAdapter( - private val layoutInflater: LayoutInflater, - private val onlyFavorites: Boolean = false + private val layoutInflater: LayoutInflater ) : RecyclerView.Adapter<Holder>() { companion object { @@ -57,22 +56,21 @@ class ControlAdapter( } } - var modelList: List<ElementWrapper> = emptyList() - private var favoritesModel: FavoriteModel? = null + private var model: ControlsModel? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { return when (viewType) { TYPE_CONTROL -> { ControlHolder( - layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply { - layoutParams.apply { - width = ViewGroup.LayoutParams.MATCH_PARENT - } - elevation = 15f - }, - { id, favorite -> - favoritesModel?.changeFavoriteStatus(id, favorite) - }) + layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply { + layoutParams.apply { + width = ViewGroup.LayoutParams.MATCH_PARENT + } + elevation = 15f + } + ) { id, favorite -> + model?.changeFavoriteStatus(id, favorite) + } } TYPE_ZONE -> { ZoneHolder(layoutInflater.inflate(R.layout.controls_zone_header, parent, false)) @@ -81,27 +79,26 @@ class ControlAdapter( } } - fun changeFavoritesModel(favoritesModel: FavoriteModel) { - this.favoritesModel = favoritesModel - if (onlyFavorites) { - modelList = favoritesModel.favorites - } else { - modelList = favoritesModel.all - } + fun changeModel(model: ControlsModel) { + this.model = model notifyDataSetChanged() } - override fun getItemCount() = modelList.size + override fun getItemCount() = model?.elements?.size ?: 0 override fun onBindViewHolder(holder: Holder, index: Int) { - holder.bindData(modelList[index]) + model?.let { + holder.bindData(it.elements[index]) + } } override fun getItemViewType(position: Int): Int { - return when (modelList[position]) { - is ZoneNameWrapper -> TYPE_ZONE - is ControlWrapper -> TYPE_CONTROL - } + model?.let { + return when (it.elements.get(position)) { + is ZoneNameWrapper -> TYPE_ZONE + is ControlWrapper -> TYPE_CONTROL + } + } ?: throw IllegalStateException("Getting item type for null model") } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index af4a977022ae..2c014498fdc2 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -26,11 +26,9 @@ import android.view.ViewStub import android.widget.Button import android.widget.TextView import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.controls.controller.ControlInfo import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.settings.CurrentUserTracker @@ -51,33 +49,10 @@ class ControlsFavoritingActivity @Inject constructor( private lateinit var recyclerViewAll: RecyclerView private lateinit var adapterAll: ControlAdapter - private lateinit var recyclerViewFavorites: RecyclerView - private lateinit var adapterFavorites: ControlAdapter - private lateinit var errorText: TextView + private lateinit var statusText: TextView + private var model: ControlsModel? = null private var component: ComponentName? = null - private var currentModel: FavoriteModel? = null - private var itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback( - /* dragDirs */ ItemTouchHelper.UP - or ItemTouchHelper.DOWN - or ItemTouchHelper.LEFT - or ItemTouchHelper.RIGHT, - /* swipeDirs */0 - ) { - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - return currentModel?.onMoveItem( - viewHolder.layoutPosition, target.layoutPosition) != null - } - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {} - - override fun isItemViewSwipeEnabled() = false - } - private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { private val startingUser = controller.currentUserId @@ -89,6 +64,10 @@ class ControlsFavoritingActivity @Inject constructor( } } + override fun onBackPressed() { + finish() + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.controls_management) @@ -99,21 +78,27 @@ class ControlsFavoritingActivity @Inject constructor( val app = intent.getCharSequenceExtra(EXTRA_APP) component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME) - errorText = requireViewById(R.id.error_message) + statusText = requireViewById(R.id.status_message) - setUpRecyclerViews() + setUpRecyclerView() requireViewById<TextView>(R.id.title).text = app?.let { it } ?: resources.getText(R.string.controls_favorite_default_title) requireViewById<TextView>(R.id.subtitle).text = resources.getText(R.string.controls_favorite_subtitle) + requireViewById<Button>(R.id.other_apps).apply { + visibility = View.VISIBLE + setOnClickListener { + this@ControlsFavoritingActivity.onBackPressed() + } + } + requireViewById<Button>(R.id.done).setOnClickListener { if (component == null) return@setOnClickListener - val favoritesForStorage = currentModel?.favorites?.map { - with(it.controlStatus.control) { - ControlInfo(component!!, controlId, title, deviceType) - } + val favoritesForStorage = model?.favorites?.map { + it.componentName = component!! + it.build() } if (favoritesForStorage != null) { controller.replaceFavoritesForComponent(component!!, favoritesForStorage) @@ -122,20 +107,22 @@ class ControlsFavoritingActivity @Inject constructor( } component?.let { + statusText.text = resources.getText(com.android.internal.R.string.loading) controller.loadForComponent(it, Consumer { data -> val allControls = data.allControls val favoriteKeys = data.favoritesIds val error = data.errorOnLoad executor.execute { - val favoriteModel = FavoriteModel( - allControls, - favoriteKeys, - allAdapter = adapterAll, - favoritesAdapter = adapterFavorites) - adapterAll.changeFavoritesModel(favoriteModel) - adapterFavorites.changeFavoritesModel(favoriteModel) - currentModel = favoriteModel - errorText.visibility = if (error) View.VISIBLE else View.GONE + val emptyZoneString = resources.getText( + R.string.controls_favorite_other_zone_header) + val model = AllModel(allControls, favoriteKeys, emptyZoneString) + adapterAll.changeModel(model) + this.model = model + if (error) { + statusText.text = resources.getText(R.string.controls_favorite_load_error) + } else { + statusText.visibility = View.GONE + } } }) } @@ -143,7 +130,7 @@ class ControlsFavoritingActivity @Inject constructor( currentUserTracker.startTracking() } - private fun setUpRecyclerViews() { + private fun setUpRecyclerView() { val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin) val itemDecorator = MarginItemDecorator(margin, margin) val layoutInflater = LayoutInflater.from(applicationContext) @@ -156,14 +143,6 @@ class ControlsFavoritingActivity @Inject constructor( } addItemDecoration(itemDecorator) } - - adapterFavorites = ControlAdapter(layoutInflater, true) - recyclerViewFavorites = requireViewById<RecyclerView>(R.id.listFavorites).apply { - layoutManager = GridLayoutManager(applicationContext, 2) - adapter = adapterFavorites - addItemDecoration(itemDecorator) - } - ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(recyclerViewFavorites) } override fun onDestroy() { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt index 882382cc4ade..53f301939435 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.management +import android.app.ActivityManager import android.content.ComponentName import android.content.Context import android.content.pm.ServiceInfo @@ -72,7 +73,7 @@ class ControlsListingControllerImpl @VisibleForTesting constructor( private var availableServices = emptyList<ServiceInfo>() - override var currentUserId = context.userId + override var currentUserId = ActivityManager.getCurrentUser() private set private val serviceListingCallback = ServiceListing.Callback { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt new file mode 100644 index 000000000000..a995a2ebfd25 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.management + +import com.android.systemui.controls.ControlStatus +import com.android.systemui.controls.controller.ControlInfo + +/** + * Model for using with [ControlAdapter]. + * + * Implementations of this interface provide different views of the controls to show. + */ +interface ControlsModel { + + /** + * List of favorites (builders) in order. + * + * This should be obtained prior to storing the favorites using + * [ControlsController.replaceFavoritesForComponent]. + */ + val favorites: List<ControlInfo.Builder> + + /** + * List of all the elements to display by the corresponding [RecyclerView]. + */ + val elements: List<ElementWrapper> + + /** + * Change the favorite status of a particular control. + */ + fun changeFavoriteStatus(controlId: String, favorite: Boolean) {} + + /** + * Move an item (in elements) from one position to another. + */ + fun onMoveItem(from: Int, to: Int) {} +} + +/** + * Wrapper classes for the different types of elements shown in the [RecyclerView]s in + * [ControlAdapter]. + */ +sealed class ElementWrapper +data class ZoneNameWrapper(val zoneName: CharSequence) : ElementWrapper() +data class ControlWrapper(val controlStatus: ControlStatus) : ElementWrapper()
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt index ad4bdefdff3e..098caf61a873 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt @@ -21,6 +21,7 @@ import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.ViewStub +import android.widget.Button import android.widget.TextView import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -86,6 +87,10 @@ class ControlsProviderSelectorActivity @Inject constructor( requireViewById<TextView>(R.id.subtitle).text = resources.getText(R.string.controls_providers_subtitle) + requireViewById<Button>(R.id.done).setOnClickListener { + this@ControlsProviderSelectorActivity.finishAffinity() + } + currentUserTracker.startTracking() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt index 6bade0aeb998..5c51e3dbe4ac 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt @@ -142,12 +142,4 @@ class CharSequenceComparator : Comparator<CharSequence> { else if (p0 != null && p1 == null) return 1 return p0.toString().compareTo(p1.toString()) } -} - -/** - * Wrapper classes for the different types of elements shown in the [RecyclerView]s in - * [ControlsFavoritingActivity]. - */ -sealed class ElementWrapper -data class ZoneNameWrapper(val zoneName: CharSequence) : ElementWrapper() -data class ControlWrapper(val controlStatus: ControlStatus) : ElementWrapper()
\ No newline at end of file +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 7c0033c1d4ec..6c502d273a1c 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -20,6 +20,7 @@ import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; import android.app.INotificationManager; import android.content.Context; +import android.content.SharedPreferences; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.display.NightDisplayListener; import android.os.Handler; @@ -27,6 +28,7 @@ import android.os.HandlerThread; import android.os.ServiceManager; import android.util.DisplayMetrics; import android.view.Choreographer; +import android.view.IWindowManager; import android.view.LayoutInflater; import android.view.WindowManager; @@ -34,6 +36,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.util.NotificationMessagingUtil; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; +import com.android.systemui.Prefs; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.AlwaysOnDisplayPolicy; @@ -45,6 +48,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.DevicePolicyManagerWrapper; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DataSaverController; @@ -79,6 +83,13 @@ public class DependencyProvider { /** */ @Provides + @Main + public SharedPreferences provideSharePreferences(Context context) { + return Prefs.get(context); + } + + /** */ + @Provides public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) { return new AmbientDisplayConfiguration(context); } @@ -157,6 +168,14 @@ public class DependencyProvider { return new ConfigurationControllerImpl(context); } + /** */ + @Singleton + @Provides + public AutoHideController provideAutoHideController(Context context, + @Main Handler mainHandler, IWindowManager iWindowManager) { + return new AutoHideController(context, mainHandler, iWindowManager); + } + @Singleton @Provides public ActivityManagerWrapper provideActivityManagerWrapper() { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java index 3aa14a31a5d9..1ec979c4cd76 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java @@ -30,6 +30,8 @@ import android.app.trust.TrustManager; import android.content.ContentResolver; import android.content.Context; import android.content.pm.IPackageManager; +import android.content.pm.LauncherApps; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.SensorPrivacyManager; import android.media.AudioManager; @@ -167,6 +169,12 @@ public class SystemServicesModule { return LatencyTracker.getInstance(context); } + @Singleton + @Provides + static LauncherApps provideLauncherApps(Context context) { + return context.getSystemService(LauncherApps.class); + } + @SuppressLint("MissingPermission") @Singleton @Provides @@ -184,6 +192,12 @@ public class SystemServicesModule { @Singleton @Provides + static PackageManager providePackageManager(Context context) { + return context.getPackageManager(); + } + + @Singleton + @Provides static PackageManagerWrapper providePackageManagerWrapper() { return PackageManagerWrapper.getInstance(); } @@ -209,6 +223,7 @@ public class SystemServicesModule { @Provides @Singleton + @Nullable static TelecomManager provideTelecomManager(Context context) { return context.getSystemService(TelecomManager.class); } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 4fba83a4cc9c..24f505d5a395 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -92,6 +92,7 @@ import com.android.systemui.MultiListLayout; import com.android.systemui.MultiListLayout.MultiListAdapter; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -189,6 +190,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private ControlsUiController mControlsUiController; private final IWindowManager mIWindowManager; private final Executor mBackgroundExecutor; + private final ControlsListingController mControlsListingController; + private boolean mAnyControlsProviders = false; /** * @param context everything needs a context :( @@ -203,12 +206,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, ConfigurationController configurationController, ActivityStarter activityStarter, KeyguardStateController keyguardStateController, UserManager userManager, TrustManager trustManager, IActivityManager iActivityManager, - TelecomManager telecomManager, MetricsLogger metricsLogger, + @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, BlurUtils blurUtils, SysuiColorExtractor colorExtractor, IStatusBarService statusBarService, NotificationShadeWindowController notificationShadeWindowController, ControlsUiController controlsUiController, IWindowManager iWindowManager, - @Background Executor backgroundExecutor) { + @Background Executor backgroundExecutor, + ControlsListingController controlsListingController) { mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme); mWindowManagerFuncs = windowManagerFuncs; mAudioManager = audioManager; @@ -232,6 +236,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mControlsUiController = controlsUiController; mIWindowManager = iWindowManager; mBackgroundExecutor = backgroundExecutor; + mControlsListingController = controlsListingController; // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -268,6 +273,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } }); + + mControlsListingController.addCallback(list -> mAnyControlsProviders = !list.isEmpty()); } /** @@ -561,13 +568,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public void onPress() { mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU); - Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent(null /* number */); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - | Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, - EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU); - mContext.startActivityAsUser(intent, UserHandle.CURRENT); + if (mTelecomManager != null) { + Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent( + null /* number */); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE, + EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); + } } } @@ -1914,6 +1924,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean shouldShowControls() { return mKeyguardStateController.isUnlocked() - && mControlsUiController.getAvailable(); + && mControlsUiController.getAvailable() + && mAnyControlsProviders; } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index d688f0aa12e1..c129035e66a7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -96,6 +96,7 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.InjectionInflationController; import java.io.FileDescriptor; @@ -378,6 +379,17 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { private IKeyguardDrawnCallback mDrawnCallback; private CharSequence mCustomMessage; + private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (properties.getKeyset().contains(NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN)) { + mShowHomeOverLockscreen = properties.getBoolean( + NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, true /* defaultValue */); + } + } + }; + KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { @Override @@ -692,6 +704,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { } }; + private DeviceConfigProxy mDeviceConfig; + /** * Injected constructor. See {@link KeyguardModule}. */ @@ -705,7 +719,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { DismissCallbackRegistry dismissCallbackRegistry, KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager, @UiBackground Executor uiBgExecutor, PowerManager powerManager, - TrustManager trustManager) { + TrustManager trustManager, + DeviceConfigProxy deviceConfig) { super(context); mFalsingManager = falsingManager; mLockPatternUtils = lockPatternUtils; @@ -718,20 +733,15 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mPM = powerManager; mTrustManager = trustManager; dumpManager.registerDumpable(getClass().getName(), this); - mShowHomeOverLockscreen = DeviceConfig.getBoolean( + mDeviceConfig = deviceConfig; + mShowHomeOverLockscreen = mDeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, /* defaultValue = */ true); - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, - new DeviceConfig.OnPropertiesChangedListener() { - @Override - public void onPropertiesChanged(DeviceConfig.Properties properties) { - if (properties.getKeyset().contains(NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN)) { - mShowHomeOverLockscreen = properties.getBoolean( - NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, true /* defaultValue */); - } - } - }); + mDeviceConfig.addOnPropertiesChangedListener( + DeviceConfig.NAMESPACE_SYSTEMUI, + mHandler::post, + mOnPropertiesChangedListener); } public void userActivity() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index d7af36010dfa..367f46406ee8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -31,6 +31,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.util.DeviceConfigProxy; import java.util.concurrent.Executor; @@ -62,7 +63,8 @@ public class KeyguardModule { DumpManager dumpManager, PowerManager powerManager, TrustManager trustManager, - @UiBackground Executor uiBgExecutor) { + @UiBackground Executor uiBgExecutor, + DeviceConfigProxy deviceConfig) { return new KeyguardViewMediator( context, falsingManager, @@ -75,6 +77,7 @@ public class KeyguardModule { dumpManager, uiBgExecutor, powerManager, - trustManager); + trustManager, + deviceConfig); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index b5fd406de368..1fc1fe45bbb3 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -99,6 +99,10 @@ public class PipAnimationController { return mCurrentAnimator; } + PipTransitionAnimator getCurrentAnimator() { + return mCurrentAnimator; + } + private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) { animator.setInterpolator(mFastOutSlowInInterpolator); animator.setFloatValues(FRACTION_START, FRACTION_END); diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 8c3ccaab8249..1ae3d4f482f4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -336,9 +336,17 @@ public class PipBoundsHandler { // Save the snap fraction and adjust the size based on the new aspect ratio. final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds)); - final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize; - final Size size = mSnapAlgorithm.getSizeForAspectRatio( - new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize); + final int minEdgeSize; + final Size size; + if (useCurrentMinEdgeSize) { + minEdgeSize = mCurrentMinSize; + size = mSnapAlgorithm.getSizeForAspectRatio( + new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize); + } else { + minEdgeSize = mDefaultMinSize; + size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize, + mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight); + } final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f); final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f); diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 1555153e8d4f..665146e6ba0d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -166,7 +166,22 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { * Updates the display dimension with given {@link DisplayInfo} */ public void onDisplayInfoChanged(DisplayInfo displayInfo) { - mDisplayBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); + final Rect newDisplayBounds = new Rect(0, 0, + displayInfo.logicalWidth, displayInfo.logicalHeight); + if (!mDisplayBounds.equals(newDisplayBounds)) { + // Updates the exiting PiP animation in case the screen rotation changes in the middle. + // It's a legit case that PiP window is in portrait mode on home screen and + // the application requests landscape onces back to fullscreen mode. + final PipAnimationController.PipTransitionAnimator animator = + mPipAnimationController.getCurrentAnimator(); + if (animator != null + && animator.getAnimationType() == ANIM_TYPE_BOUNDS + && animator.getDestinationBounds().equals(mDisplayBounds)) { + animator.updateEndValue(newDisplayBounds); + animator.setDestinationBounds(newDisplayBounds); + } + } + mDisplayBounds.set(newDisplayBounds); } /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index e98dec0835bf..8ada3c393222 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -48,6 +48,7 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.wm.DisplayChangeController; import com.android.systemui.wm.DisplayController; @@ -68,7 +69,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private IActivityManager mActivityManager; private Handler mHandler = new Handler(); - private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener(); private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); private final Rect mTmpInsetBounds = new Rect(); private final Rect mTmpNormalBounds = new Rect(); @@ -204,12 +204,14 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Inject public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, DisplayController displayController, - FloatingContentCoordinator floatingContentCoordinator) { + FloatingContentCoordinator floatingContentCoordinator, + DeviceConfigProxy deviceConfig) { mContext = context; mActivityManager = ActivityManager.getService(); try { - WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener); + WindowManagerWrapper.getInstance().addPinnedStackListener( + new PipManagerPinnedStackListener()); } catch (RemoteException e) { Log.e(TAG, "Failed to register pinned stack listener", e); } @@ -225,7 +227,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mInputConsumerController); mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager, mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer, - floatingContentCoordinator); + floatingContentCoordinator, deviceConfig); mAppOpsListener = new PipAppOpsListener(context, mActivityManager, mTouchHandler.getMotionHelper()); displayController.addDisplayChangingController(mRotationController); @@ -339,12 +341,15 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private void updateMovementBounds(Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment) { - // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler first. + // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before + // passing to mTouchHandler, mTouchHandler would rely on the bounds calculated by + // mPipBoundsHandler with up-to-dated information mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, animatingBounds, mTmpDisplayInfo); mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, animatingBounds, fromImeAdjustment, fromShelfAdjustment, mTmpDisplayInfo.rotation); + mPipTaskOrganizer.onDisplayInfoChanged(mTmpDisplayInfo); } public void dump(PrintWriter pw) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 91f539c3a13d..980d18b6a7e0 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -411,11 +411,9 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call } private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) { - if (offset == 0) { - return; - } SomeArgs args = SomeArgs.obtain(); args.arg1 = originalBounds; + // offset would be zero if triggered from screen rotation. args.argi1 = offset; args.argi2 = duration; mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args)); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java index 9fb623471bf7..389793e6fc94 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java @@ -41,6 +41,7 @@ import android.view.MotionEvent; import com.android.internal.policy.TaskResizingAlgorithm; import com.android.systemui.R; import com.android.systemui.pip.PipBoundsHandler; +import com.android.systemui.util.DeviceConfigProxy; import java.util.concurrent.Executor; @@ -77,7 +78,8 @@ public class PipResizeGestureHandler { private int mCtrlType; public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler, - PipTouchHandler pipTouchHandler, PipMotionHelper motionHelper) { + PipTouchHandler pipTouchHandler, PipMotionHelper motionHelper, + DeviceConfigProxy deviceConfig) { final Resources res = context.getResources(); context.getDisplay().getMetrics(mDisplayMetrics); mDisplayId = context.getDisplayId(); @@ -93,7 +95,7 @@ public class PipResizeGestureHandler { DeviceConfig.NAMESPACE_SYSTEMUI, PIP_USER_RESIZE, /* defaultValue = */ false); - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor, + deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor, new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 79a25b2269f6..3f73d0194cd6 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -48,6 +48,7 @@ import com.android.systemui.pip.PipSnapAlgorithm; import com.android.systemui.pip.PipTaskOrganizer; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.FloatingContentCoordinator; import java.io.PrintWriter; @@ -67,6 +68,8 @@ public class PipTouchHandler { // Allow dragging the PIP to a location to close it private final boolean mEnableDismissDragToEdge; + // Allow PIP to resize to a slightly bigger state upon touch + private final boolean mEnableResize; private final Context mContext; private final IActivityManager mActivityManager; private final PipBoundsHandler mPipBoundsHandler; @@ -162,7 +165,8 @@ public class PipTouchHandler { InputConsumerController inputConsumerController, PipBoundsHandler pipBoundsHandler, PipTaskOrganizer pipTaskOrganizer, - FloatingContentCoordinator floatingContentCoordinator) { + FloatingContentCoordinator floatingContentCoordinator, + DeviceConfigProxy deviceConfig) { // Initialize the Pip input consumer mContext = context; mActivityManager = activityManager; @@ -177,7 +181,8 @@ public class PipTouchHandler { mMotionHelper = new PipMotionHelper(mContext, activityTaskManager, pipTaskOrganizer, mMenuController, mSnapAlgorithm, mFlingAnimationUtils, floatingContentCoordinator); mPipResizeGestureHandler = - new PipResizeGestureHandler(context, pipBoundsHandler, this, mMotionHelper); + new PipResizeGestureHandler(context, pipBoundsHandler, this, mMotionHelper, + deviceConfig); mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler, () -> mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(), mMovementBounds, true /* allowMenuTimeout */, willResizeMenu())); @@ -188,6 +193,7 @@ public class PipTouchHandler { mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset); mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge); + mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu); // Register the listener for input consumer touch events inputConsumerController.setInputListener(this::handleTouchEvent); @@ -263,6 +269,10 @@ public class PipTouchHandler { public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect curBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) { final int bottomOffset = mIsImeShowing ? mImeHeight : 0; + final boolean fromDisplayRotationChanged = (mDisplayRotation != displayRotation); + if (fromDisplayRotationChanged) { + mTouchState.reset(); + } // Re-calculate the expanded bounds mNormalBounds = normalBounds; @@ -290,14 +300,14 @@ public class PipTouchHandler { // If this is from an IME or shelf adjustment, then we should move the PiP so that it is not // occluded by the IME or shelf. - if (fromImeAdjustment || fromShelfAdjustment) { + if (fromImeAdjustment || fromShelfAdjustment || fromDisplayRotationChanged) { if (mTouchState.isUserInteracting()) { // Defer the update of the current movement bounds until after the user finishes // touching the screen } else { final float offsetBufferPx = BOTTOM_OFFSET_BUFFER_DP * mContext.getResources().getDisplayMetrics().density; - final Rect toMovementBounds = mMenuState == MENU_STATE_FULL + final Rect toMovementBounds = mMenuState == MENU_STATE_FULL && willResizeMenu() ? new Rect(expandedMovementBounds) : new Rect(normalMovementBounds); final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets; @@ -691,11 +701,12 @@ public class PipTouchHandler { }; /** - * Updates the current movement bounds based on whether the menu is currently visible. + * Updates the current movement bounds based on whether the menu is currently visible and + * resized. */ private void updateMovementBounds(int menuState) { boolean isMenuExpanded = menuState == MENU_STATE_FULL; - mMovementBounds = isMenuExpanded + mMovementBounds = isMenuExpanded && willResizeMenu() ? mExpandedMovementBounds : mNormalMovementBounds; mPipBoundsHandler.setMinEdgeSize( @@ -715,8 +726,11 @@ public class PipTouchHandler { * @return whether the menu will resize as a part of showing the full menu. */ private boolean willResizeMenu() { - return mExpandedBounds.width() != mNormalBounds.width() || - mExpandedBounds.height() != mNormalBounds.height(); + if (!mEnableResize) { + return false; + } + return mExpandedBounds.width() != mNormalBounds.width() + || mExpandedBounds.height() != mNormalBounds.height(); } public void dump(PrintWriter pw, String prefix) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index 938f9dbde6ff..17ac5e5ca47e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -28,6 +28,7 @@ import android.provider.Settings; import android.provider.Settings.Secure; import android.service.quicksettings.Tile; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import com.android.systemui.Dumpable; @@ -61,6 +62,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; import javax.inject.Inject; @@ -91,6 +93,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final ArrayList<QSFactory> mQsFactories = new ArrayList<>(); private int mCurrentUser; private final Optional<StatusBar> mStatusBarOptional; + private Context mUserContext; @Inject public QSTileHost(Context context, @@ -107,6 +110,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D QSLogger qsLogger) { mIconController = iconController; mContext = context; + mUserContext = context; mTunerService = tunerService; mPluginManager = pluginManager; mDumpManager = dumpManager; @@ -207,6 +211,9 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D return mContext; } + public Context getUserContext() { + return mUserContext; + } public TileServices getTileServices() { return mServices; @@ -227,6 +234,9 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } final List<String> tileSpecs = loadTileSpecs(mContext, newValue); int currentUser = ActivityManager.getCurrentUser(); + if (currentUser != mCurrentUser) { + mUserContext = mContext.createContextAsUser(UserHandle.of(currentUser), 0); + } if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return; mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach( tile -> { @@ -253,6 +263,13 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mQSLogger.logTileDestroyed(tileSpec, "Tile not available"); } } else { + // This means that the tile is a CustomTile AND the user is different, so let's + // destroy it + if (tile != null) { + tile.destroy(); + Log.d(TAG, "Destroying tile for wrong user: " + tileSpec); + mQSLogger.logTileDestroyed(tileSpec, "Tile for wrong user"); + } Log.d(TAG, "Creating tile: " + tileSpec); try { tile = createTile(tileSpec); @@ -273,7 +290,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } } mCurrentUser = currentUser; - List<String> currentSpecs = new ArrayList(mTileSpecs); + List<String> currentSpecs = new ArrayList<>(mTileSpecs); mTileSpecs.clear(); mTileSpecs.addAll(tileSpecs); mTiles.clear(); @@ -300,7 +317,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } public void addTile(String spec) { - changeTileSpecs(tileSpecs-> tileSpecs.add(spec)); + changeTileSpecs(tileSpecs-> !tileSpecs.contains(spec) && tileSpecs.add(spec)); } private void changeTileSpecs(Predicate<List<String>> changeFunction) { @@ -314,9 +331,12 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } public void addTile(ComponentName tile) { - List<String> newSpecs = new ArrayList<>(mTileSpecs); - newSpecs.add(0, CustomTile.toSpec(tile)); - changeTiles(mTileSpecs, newSpecs); + String spec = CustomTile.toSpec(tile); + if (!mTileSpecs.contains(spec)) { + List<String> newSpecs = new ArrayList<>(mTileSpecs); + newSpecs.add(0, spec); + changeTiles(mTileSpecs, newSpecs); + } } public void removeTile(ComponentName tile) { @@ -326,10 +346,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } public void changeTiles(List<String> previousTiles, List<String> newTiles) { - final int NP = previousTiles.size(); - final int NA = newTiles.size(); + final List<String> copy = new ArrayList<>(previousTiles); + final int NP = copy.size(); for (int i = 0; i < NP; i++) { - String tileSpec = previousTiles.get(i); + String tileSpec = copy.get(i); if (!tileSpec.startsWith(CustomTile.PREFIX)) continue; if (!newTiles.contains(tileSpec)) { ComponentName component = CustomTile.getComponentFromSpec(tileSpec); @@ -380,16 +400,26 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } final ArrayList<String> tiles = new ArrayList<String>(); boolean addedDefault = false; + Set<String> addedSpecs = new ArraySet<>(); for (String tile : tileList.split(",")) { tile = tile.trim(); if (tile.isEmpty()) continue; if (tile.equals("default")) { if (!addedDefault) { - tiles.addAll(getDefaultSpecs(context)); + List<String> defaultSpecs = getDefaultSpecs(context); + for (String spec : defaultSpecs) { + if (!addedSpecs.contains(spec)) { + tiles.add(spec); + addedSpecs.add(spec); + } + } addedDefault = true; } } else { - tiles.add(tile); + if (!addedSpecs.contains(tile)) { + tiles.add(tile); + addedSpecs.add(tile); + } } } return tiles; diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index fb89ed264628..bfac85bd4c10 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -37,8 +37,8 @@ import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.UiEventLoggerImpl; import com.android.systemui.R; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.qs.QS; @@ -86,6 +86,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene private int mY; private boolean mOpening; private boolean mIsShowingNavBackdrop; + private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); @Inject public QSCustomizer(Context context, AttributeSet attrs, @@ -187,7 +188,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen(); mX = x - containerLocation[0]; mY = y - containerLocation[1]; - MetricsLogger.visible(getContext(), MetricsProto.MetricsEvent.QS_EDIT); + mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN); isShown = true; mOpening = true; setTileSpecs(); @@ -224,7 +225,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene public void hide() { final boolean animate = mScreenLifecycle.getScreenState() != ScreenLifecycle.SCREEN_OFF; if (isShown) { - MetricsLogger.hidden(getContext(), MetricsProto.MetricsEvent.QS_EDIT); + mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED); isShown = false; mToolbar.dismissPopupMenus(); setCustomizing(false); @@ -258,7 +259,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case MENU_RESET: - MetricsLogger.action(getContext(), MetricsProto.MetricsEvent.ACTION_QS_EDIT_RESET); + mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET); reset(); break; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt new file mode 100644 index 000000000000..ff8ddec8397a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSEditEvent.kt @@ -0,0 +1,38 @@ +/* + * 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.systemui.qs.customize + +import com.android.internal.logging.UiEvent +import com.android.internal.logging.UiEventLogger + +enum class QSEditEvent(private val _id: Int) : UiEventLogger.UiEventEnum { + + @UiEvent(doc = "Tile removed from current tiles") + QS_EDIT_REMOVE(210), + @UiEvent(doc = "Tile added to current tiles") + QS_EDIT_ADD(211), + @UiEvent(doc = "Tile moved") + QS_EDIT_MOVE(212), + @UiEvent(doc = "QS customizer open") + QS_EDIT_OPEN(213), + @UiEvent(doc = "QS customizer closed") + QS_EDIT_CLOSED(214), + @UiEvent(doc = "QS tiles reset") + QS_EDIT_RESET(215); + + override fun getId() = _id +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index 3afc46045a77..58de95d7ed6d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -40,8 +40,8 @@ import androidx.recyclerview.widget.RecyclerView.ItemDecoration; import androidx.recyclerview.widget.RecyclerView.State; import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.UiEventLoggerImpl; import com.android.systemui.R; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.customize.TileAdapter.Holder; @@ -92,6 +92,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta private int mAccessibilityFromIndex; private CharSequence mAccessibilityFromLabel; private QSTileHost mHost; + private UiEventLogger mUiEventLogger = new UiEventLoggerImpl(); public TileAdapter(Context context) { mContext = context; @@ -436,20 +437,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta move(from, to, mTiles); updateDividerLocations(); if (to >= mEditIndex) { - MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE_SPEC, - strip(mTiles.get(to))); - MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_REMOVE, - from); + mUiEventLogger.log(QSEditEvent.QS_EDIT_REMOVE, 0, strip(mTiles.get(to))); } else if (from >= mEditIndex) { - MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD_SPEC, - strip(mTiles.get(to))); - MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_ADD, - to); + mUiEventLogger.log(QSEditEvent.QS_EDIT_ADD, 0, strip(mTiles.get(to))); } else { - MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE_SPEC, - strip(mTiles.get(to))); - MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_QS_EDIT_MOVE, - to); + mUiEventLogger.log(QSEditEvent.QS_EDIT_MOVE, 0, strip(mTiles.get(to))); } saveSpecs(mHost); return true; diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 21a424c77a05..3b27fb76bcc6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -20,6 +20,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; import android.app.ActivityManager; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -72,15 +73,19 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener private android.graphics.drawable.Icon mDefaultIcon; private CharSequence mDefaultLabel; + private final Context mUserContext; + private boolean mListening; private boolean mIsTokenGranted; private boolean mIsShowingDialog; - private CustomTile(QSTileHost host, String action) { + private CustomTile(QSTileHost host, String action, Context userContext) { super(host); mWindowManager = WindowManagerGlobal.getWindowManagerService(); mComponent = ComponentName.unflattenFromString(action); mTile = new Tile(); + mUserContext = userContext; + mUser = mUserContext.getUserId(); updateDefaultTileAndIcon(); mServiceManager = host.getTileServices().getTileWrapper(this); if (mServiceManager.isToggleableTile()) { @@ -90,7 +95,6 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mService = mServiceManager.getTileService(); mServiceManager.setTileChangeListener(this); - mUser = ActivityManager.getCurrentUser(); } @Override @@ -100,7 +104,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener private void updateDefaultTileAndIcon() { try { - PackageManager pm = mContext.getPackageManager(); + PackageManager pm = mUserContext.getPackageManager(); int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DIRECT_BOOT_AWARE; if (isSystemApp(pm)) { flags |= PackageManager.MATCH_DISABLED_COMPONENTS; @@ -318,15 +322,16 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener state.state = tileState; Drawable drawable; try { - drawable = mTile.getIcon().loadDrawable(mContext); + drawable = mTile.getIcon().loadDrawable(mUserContext); } catch (Exception e) { Log.w(TAG, "Invalid icon, forcing into unavailable state"); state.state = Tile.STATE_UNAVAILABLE; - drawable = mDefaultIcon.loadDrawable(mContext); + drawable = mDefaultIcon.loadDrawable(mUserContext); } final Drawable drawableF = drawable; state.iconSupplier = () -> { + if (drawableF == null) return null; Drawable.ConstantState cs = drawableF.getConstantState(); if (cs != null) { return new DrawableIcon(cs.newDrawable()); @@ -387,7 +392,7 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener return ComponentName.unflattenFromString(action); } - public static CustomTile create(QSTileHost host, String spec) { + public static CustomTile create(QSTileHost host, String spec, Context userContext) { if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) { throw new IllegalArgumentException("Bad custom tile spec: " + spec); } @@ -395,6 +400,6 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener if (action.isEmpty()) { throw new IllegalArgumentException("Empty custom tile spec action"); } - return new CustomTile(host, action); + return new CustomTile(host, action, userContext); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index 17b0251837e7..aa51771864b2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -279,6 +279,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements if (mPackageReceiverRegistered.get() || mUserReceiverRegistered.get()) { stopPackageListening(); } + mChangeListener = null; } private void handleDeath() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 554672d88052..1b8717b5049c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -178,7 +178,9 @@ public class QSFactoryImpl implements QSFactory { } // Custom tiles - if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec); + if (tileSpec.startsWith(CustomTile.PREFIX)) { + return CustomTile.create(mHost, tileSpec, mHost.getUserContext()); + } // Debug tiles. if (Build.IS_DEBUGGABLE) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index ebf45a66a23a..9f7b84aa62c1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -53,6 +53,7 @@ import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysUIToast; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile.BooleanState; @@ -79,6 +80,7 @@ public class DndTile extends QSTileImpl<BooleanState> { private final ZenModeController mController; private final DndDetailAdapter mDetailAdapter; private final ActivityStarter mActivityStarter; + private final SharedPreferences mSharedPreferences; private final BroadcastDispatcher mBroadcastDispatcher; private boolean mListening; @@ -87,10 +89,12 @@ public class DndTile extends QSTileImpl<BooleanState> { @Inject public DndTile(QSHost host, ZenModeController zenModeController, - ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher) { + ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher, + @Main SharedPreferences sharedPreferences) { super(host); mController = zenModeController; mActivityStarter = activityStarter; + mSharedPreferences = sharedPreferences; mDetailAdapter = new DndDetailAdapter(); mBroadcastDispatcher = broadcastDispatcher; broadcastDispatcher.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE)); @@ -111,16 +115,16 @@ public class DndTile extends QSTileImpl<BooleanState> { Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible); } - public static boolean isVisible(Context context) { - return Prefs.getBoolean(context, Prefs.Key.DND_TILE_VISIBLE, false /* defaultValue */); + public static boolean isVisible(SharedPreferences prefs) { + return prefs.getBoolean(Prefs.Key.DND_TILE_VISIBLE, false /* defaultValue */); } public static void setCombinedIcon(Context context, boolean combined) { Prefs.putBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON, combined); } - public static boolean isCombinedIcon(Context context) { - return Prefs.getBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON, + public static boolean isCombinedIcon(SharedPreferences sharedPreferences) { + return sharedPreferences.getBoolean(Prefs.Key.DND_TILE_COMBINED_ICON, false /* defaultValue */); } @@ -301,7 +305,7 @@ public class DndTile extends QSTileImpl<BooleanState> { @Override public boolean isAvailable() { - return isVisible(mContext); + return isVisible(mSharedPreferences); } private final OnSharedPreferenceChangeListener mPrefListener diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java index 2557226d07bd..5dcb4e3b1fb9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java @@ -16,9 +16,9 @@ package com.android.systemui.qs.tiles; -import android.content.Context; import android.content.Intent; import android.content.res.Configuration; +import android.content.res.Resources; import android.provider.Settings; import android.service.quicksettings.Tile; import android.widget.Switch; @@ -81,11 +81,11 @@ public class RotationLockTile extends QSTileImpl<BooleanState> { } public static boolean isCurrentOrientationLockPortrait(RotationLockController controller, - Context context) { + Resources resources) { int lockOrientation = controller.getRotationLockOrientation(); if (lockOrientation == Configuration.ORIENTATION_UNDEFINED) { // Freely rotating device; use current rotation - return context.getResources().getConfiguration().orientation + return resources.getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE; } else { return lockOrientation != Configuration.ORIENTATION_LANDSCAPE; diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 39bfd5a8b6db..f1695017a883 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -206,7 +206,7 @@ public class WifiTile extends QSTileImpl<SignalState> { state.icon = ResourceIcon.get(cb.wifiSignalIconId); state.label = removeDoubleQuotes(cb.ssid); } else if (wifiNotConnected) { - state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disconnected); + state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); state.label = r.getString(R.string.quick_settings_wifi_label); } else { state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK); diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 626f298055a0..390ac0969b21 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -63,7 +63,7 @@ import javax.inject.Inject; /** * A service which records the device screen and optionally microphone input. */ -public class RecordingService extends Service { +public class RecordingService extends Service implements MediaRecorder.OnInfoListener { public static final int REQUEST_CODE = 2; private static final int NOTIFICATION_ID = 1; @@ -85,6 +85,8 @@ public class RecordingService extends Service { private static final int VIDEO_FRAME_RATE = 30; private static final int AUDIO_BIT_RATE = 16; private static final int AUDIO_SAMPLE_RATE = 44100; + private static final int MAX_DURATION_MS = 60 * 60 * 1000; + private static final long MAX_FILESIZE_BYTES = 5000000000L; private final RecordingController mController; private MediaProjection mMediaProjection; @@ -250,6 +252,8 @@ public class RecordingService extends Service { mMediaRecorder.setVideoSize(screenWidth, screenHeight); mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE); mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE); + mMediaRecorder.setMaxDuration(MAX_DURATION_MS); + mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES); // Set up audio if (mUseAudio) { @@ -274,6 +278,7 @@ public class RecordingService extends Service { null, null); + mMediaRecorder.setOnInfoListener(this); mMediaRecorder.start(); mController.updateState(true); } catch (IOException e) { @@ -454,4 +459,10 @@ public class RecordingService extends Service { return new Intent(context, RecordingService.class).setAction(ACTION_DELETE) .putExtra(EXTRA_PATH, path); } + + @Override + public void onInfo(MediaRecorder mr, int what, int extra) { + Log.d(TAG, "Media recorder info: " + what); + onStartCommand(getStopIntent(this), 0, 0); + } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index f06cd54f7756..7c770f43fb57 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -514,12 +514,17 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset 1, cornerScale, mFastOutSlowIn.getInterpolation(t / scalePct)); mScreenshotView.setScaleX(scale); mScreenshotView.setScaleY(scale); + } else { + mScreenshotView.setScaleX(cornerScale); + mScreenshotView.setScaleY(cornerScale); } if (t < xPositionPct) { float xCenter = MathUtils.lerp(startPos.x, finalPos.x, mFastOutSlowIn.getInterpolation(t / xPositionPct)); mScreenshotView.setX(xCenter - width * mScreenshotView.getScaleX() / 2f); + } else { + mScreenshotView.setX(finalPos.x - width * mScreenshotView.getScaleX() / 2f); } float yCenter = MathUtils.lerp(startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t)); @@ -544,6 +549,10 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); + mScreenshotView.setScaleX(cornerScale); + mScreenshotView.setScaleY(cornerScale); + mScreenshotView.setX(finalPos.x - width * cornerScale / 2f); + mScreenshotView.setY(finalPos.y - height * cornerScale / 2f); Rect bounds = new Rect(); mScreenshotView.getBoundsOnScreen(bounds); mDismissButton.setX(bounds.right - mDismissButtonSize / 2f); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 56cdff43e255..27b799bc02a3 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -401,6 +401,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, return; } mMinimized = minimized; + WindowManagerProxy.applyPrimaryFocusable(mSplits, !mMinimized); mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable); updateTouchable(); }); @@ -504,6 +505,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, final boolean wasMinimized = mMinimized; mMinimized = true; setHomeStackResizable(mSplits.mSecondary.isResizable()); + WindowManagerProxy.applyPrimaryFocusable(mSplits, false /* focusable */); if (!inSplitMode()) { // Wasn't in split-mode yet, so enter now. if (DEBUG) { @@ -521,6 +523,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, } void ensureNormalSplit() { + if (mMinimized) { + WindowManagerProxy.applyPrimaryFocusable(mSplits, true /* focusable */); + } if (!inSplitMode()) { // Wasn't in split-mode, so enter now. if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index 76857337f73e..167c33abac6e 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -292,10 +292,23 @@ public class WindowManagerProxy { for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) { wct.setBounds(freeHomeAndRecents.get(i).token, null); } + // Reset focusable to true + wct.setFocusable(tiles.mPrimary.token, true /* focusable */); ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct, null /* organizer */); } catch (RemoteException e) { Log.w(TAG, "Failed to remove stack: " + e); } } + + static void applyPrimaryFocusable(SplitScreenTaskOrganizer splits, boolean focusable) { + try { + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setFocusable(splits.mPrimary.token, focusable); + ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct, + null /* organizer */); + } catch (RemoteException e) { + Log.w(TAG, "Error setting focusability: " + e); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AutoHideUiElement.java b/packages/SystemUI/src/com/android/systemui/statusbar/AutoHideUiElement.java new file mode 100644 index 000000000000..af04135c7f4d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AutoHideUiElement.java @@ -0,0 +1,53 @@ +/* + * 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.systemui.statusbar; + +/** + * Common interface for a UI element controlled by + * {@link com.android.systemui.statusbar.phone.AutoHideController}. These UI elements automatically + * hidden by {@link com.android.systemui.statusbar.phone.AutoHideController} when in some transient + * state. + */ +public interface AutoHideUiElement { + + /** + * Ensures that the {@link AutoHideUiElement} reflects the current expected state. This + * method will be posted as a {@link Runnable} in the main thread. + */ + void synchronizeState(); + + /** + * The {@link com.android.systemui.statusbar.phone.AutoHideController} is responsible for + * automatically hiding ui elements that are only shown transiently. This method determines + * whether a manual touch should also hide the ui elements that are temporarily visible. + * + * Note that all {@link AutoHideUiElement} instances should return true for a manual touch to + * trigger {@link #hide()} on the ui elements. + */ + default boolean shouldHideOnTouch() { + return true; + } + + /** Returns true if the {@link AutoHideUiElement} is visible. */ + boolean isVisible(); + + /** + * Called to hide the {@link AutoHideUiElement} through the + * {@link com.android.systemui.statusbar.phone.AutoHideController}. + */ + void hide(); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java index a8188b3ca35c..ebac4b293522 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java @@ -149,7 +149,6 @@ public class NavigationBarController implements Callbacks { AutoHideController autoHideController = isOnDefaultDisplay ? Dependency.get(AutoHideController.class) : new AutoHideController(context, mHandler, - Dependency.get(NotificationRemoteInputManager.class), Dependency.get(IWindowManager.class)); navBar.setAutoHideController(autoHideController); navBar.restoreAppearanceAndTransientState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java index b43fe73945cd..047edd26c689 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java @@ -20,6 +20,7 @@ import static com.android.systemui.statusbar.RemoteInputController.processForRem import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; import static com.android.systemui.statusbar.phone.StatusBar.DEBUG; +import android.annotation.NonNull; import android.annotation.SuppressLint; import android.app.NotificationManager; import android.content.ComponentName; @@ -161,6 +162,15 @@ public class NotificationListener extends NotificationListenerWithPlugins { } } + public final void unsnoozeNotification(@NonNull String key) { + if (!isBound()) return; + try { + getNotificationInterface().unsnoozeNotificationFromSystemListener(mWrapper, key); + } catch (android.os.RemoteException ex) { + Log.v(TAG, "Unable to contact notification manager", ex); + } + } + public void registerAsSystemService() { try { registerAsSystemService(mContext, @@ -195,7 +205,8 @@ public class NotificationListener extends NotificationListenerWithPlugins { new ArrayList<>(), false, false, - false + false, + null ); } return ranking; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index f8db922e8758..3d7beea7cd6f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -65,6 +65,7 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ScrimState; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.DeviceConfigProxy; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -183,7 +184,8 @@ public class NotificationMediaManager implements Dumpable { NotificationEntryManager notificationEntryManager, MediaArtworkProcessor mediaArtworkProcessor, KeyguardBypassController keyguardBypassController, - @Main Executor mainExecutor) { + @Main Executor mainExecutor, + DeviceConfigProxy deviceConfig) { mContext = context; mMediaArtworkProcessor = mediaArtworkProcessor; mKeyguardBypassController = keyguardBypassController; @@ -212,7 +214,8 @@ public class NotificationMediaManager implements Dumpable { public void onEntryRemoved( NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { onNotificationRemoved(entry.getKey()); } }); @@ -221,7 +224,7 @@ public class NotificationMediaManager implements Dumpable { DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED)); - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, + deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mContext.getMainExecutor(), mPropertiesChangedListener); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index ebc2fa60d3e8..bf28040233f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -292,7 +292,8 @@ public class NotificationRemoteInputManager implements Dumpable { public void onEntryRemoved( @Nullable NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { // We're removing the notification, the smart controller can forget about it. mSmartReplyController.stopSending(entry); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 7e70c2059e60..fe2f1f3eefc5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -30,6 +30,7 @@ import com.android.systemui.bubbles.BubbleController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.dagger.StatusBarModule; +import com.android.systemui.statusbar.notification.DynamicChildBindController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; @@ -59,11 +60,12 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle private final Handler mHandler; - //TODO: change this top <Entry, List<Entry>>? - private final HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> - mTmpChildOrderMap = new HashMap<>(); + /** Re-usable map of notifications to their sorted children.*/ + private final HashMap<NotificationEntry, List<NotificationEntry>> mTmpChildOrderMap = + new HashMap<>(); // Dependencies: + private final DynamicChildBindController mDynamicChildBindController; protected final NotificationLockscreenUserManager mLockscreenUserManager; protected final NotificationGroupManager mGroupManager; protected final VisualStabilityManager mVisualStabilityManager; @@ -105,7 +107,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle KeyguardBypassController bypassController, BubbleController bubbleController, DynamicPrivacyController privacyController, - ForegroundServiceSectionController fgsSectionController) { + ForegroundServiceSectionController fgsSectionController, + DynamicChildBindController dynamicChildBindController) { mContext = context; mHandler = mainHandler; mLockscreenUserManager = notificationLockscreenUserManager; @@ -121,6 +124,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle mBubbleController = bubbleController; mDynamicPrivacyController = privacyController; privacyController.addListener(this); + mDynamicChildBindController = dynamicChildBindController; } public void setUpWithPresenter(NotificationPresenter presenter, @@ -175,13 +179,12 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle ent.getRow().setNeedsRedaction(needsRedaction); if (mGroupManager.isChildInGroupWithSummary(ent.getSbn())) { NotificationEntry summary = mGroupManager.getGroupSummary(ent.getSbn()); - List<ExpandableNotificationRow> orderedChildren = - mTmpChildOrderMap.get(summary.getRow()); + List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(summary); if (orderedChildren == null) { orderedChildren = new ArrayList<>(); - mTmpChildOrderMap.put(summary.getRow(), orderedChildren); + mTmpChildOrderMap.put(summary, orderedChildren); } - orderedChildren.add(ent.getRow()); + orderedChildren.add(ent); } else { toShow.add(ent.getRow()); } @@ -260,6 +263,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle } + mDynamicChildBindController.updateChildContentViews(mTmpChildOrderMap); mVisualStabilityManager.onReorderingFinished(); // clear the map again for the next usage mTmpChildOrderMap.clear(); @@ -274,6 +278,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle private void addNotificationChildrenAndSort() { // Let's now add all notification children which are missing boolean orderChanged = false; + ArrayList<ExpandableNotificationRow> orderedRows = new ArrayList<>(); for (int i = 0; i < mListContainer.getContainerChildCount(); i++) { View view = mListContainer.getContainerChildAt(i); if (!(view instanceof ExpandableNotificationRow)) { @@ -283,11 +288,11 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle ExpandableNotificationRow parent = (ExpandableNotificationRow) view; List<ExpandableNotificationRow> children = parent.getNotificationChildren(); - List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent); + List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(parent.getEntry()); for (int childIndex = 0; orderedChildren != null && childIndex < orderedChildren.size(); childIndex++) { - ExpandableNotificationRow childView = orderedChildren.get(childIndex); + ExpandableNotificationRow childView = orderedChildren.get(childIndex).getRow(); if (children == null || !children.contains(childView)) { if (childView.getParent() != null) { Log.wtf(TAG, "trying to add a notification child that already has " + @@ -300,11 +305,13 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle parent.addChildNotification(childView, childIndex); mListContainer.notifyGroupChildAdded(childView); } + orderedRows.add(childView); } // Finally after removing and adding has been performed we can apply the order. - orderChanged |= parent.applyChildOrder(orderedChildren, mVisualStabilityManager, + orderChanged |= parent.applyChildOrder(orderedRows, mVisualStabilityManager, mEntryManager); + orderedRows.clear(); } if (orderChanged) { mListContainer.generateChildOrderChangedEvent(); @@ -323,13 +330,13 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle ExpandableNotificationRow parent = (ExpandableNotificationRow) view; List<ExpandableNotificationRow> children = parent.getNotificationChildren(); - List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent); + List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(parent.getEntry()); if (children != null) { toRemove.clear(); for (ExpandableNotificationRow childRow : children) { if ((orderedChildren == null - || !orderedChildren.contains(childRow)) + || !orderedChildren.contains(childRow.getEntry())) && !childRow.keepInParent()) { toRemove.add(childRow); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java index cd5bb775de8c..4c99a90e7da0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java @@ -32,6 +32,7 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.SmartReplyController; +import com.android.systemui.statusbar.notification.DynamicChildBindController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; @@ -42,6 +43,7 @@ import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.tracing.ProtoTracer; +import com.android.systemui.util.DeviceConfigProxy; import java.util.concurrent.Executor; @@ -91,7 +93,8 @@ public interface StatusBarDependenciesModule { NotificationEntryManager notificationEntryManager, MediaArtworkProcessor mediaArtworkProcessor, KeyguardBypassController keyguardBypassController, - @Main Executor mainExecutor) { + @Main Executor mainExecutor, + DeviceConfigProxy deviceConfigProxy) { return new NotificationMediaManager( context, statusBarLazy, @@ -99,7 +102,8 @@ public interface StatusBarDependenciesModule { notificationEntryManager, mediaArtworkProcessor, keyguardBypassController, - mainExecutor); + mainExecutor, + deviceConfigProxy); } /** */ @@ -135,7 +139,8 @@ public interface StatusBarDependenciesModule { KeyguardBypassController bypassController, BubbleController bubbleController, DynamicPrivacyController privacyController, - ForegroundServiceSectionController fgsSectionController) { + ForegroundServiceSectionController fgsSectionController, + DynamicChildBindController dynamicChildBindController) { return new NotificationViewHierarchyManager( context, mainHandler, @@ -147,7 +152,8 @@ public interface StatusBarDependenciesModule { bypassController, bubbleController, privacyController, - fgsSectionController); + fgsSectionController, + dynamicChildBindController); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicChildBindController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicChildBindController.java new file mode 100644 index 000000000000..059d6ffa9180 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/DynamicChildBindController.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification; + +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_EXPANDED; +import static com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED; + +import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.RowContentBindParams; +import com.android.systemui.statusbar.notification.row.RowContentBindStage; + +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +/** + * Controller that binds/unbinds views content views on notification group children. + * + * We currently only show a limited number of notification children even if more exist, so we + * can save memory by freeing content views when they're not visible and binding them again when + * they get close to being visible. + * + * Eventually, when {@link NotifPipeline} takes over as the new notification pipeline, we'll have + * more control over which notifications even make it to inflation in the first place and be able + * to enforce this at an earlier stage at the level of the {@link ExpandableNotificationRow}, but + * for now, we're just doing it at the level of content views. + */ +public class DynamicChildBindController { + private final RowContentBindStage mStage; + private final int mChildBindCutoff; + + @Inject + public DynamicChildBindController(RowContentBindStage stage) { + this(stage, CHILD_BIND_CUTOFF); + } + + /** + * @param childBindCutoff the cutoff where we no longer bother having content views bound + */ + DynamicChildBindController( + RowContentBindStage stage, + int childBindCutoff) { + mStage = stage; + mChildBindCutoff = childBindCutoff; + } + + /** + * Update the child content views, unbinding content views on children that won't be visible + * and binding content views on children that will be visible eventually. + * + * @param groupNotifs map of notification summaries to their children + */ + public void updateChildContentViews( + Map<NotificationEntry, List<NotificationEntry>> groupNotifs) { + for (NotificationEntry entry : groupNotifs.keySet()) { + List<NotificationEntry> children = groupNotifs.get(entry); + for (int j = 0; j < children.size(); j++) { + NotificationEntry childEntry = children.get(j); + if (j >= mChildBindCutoff) { + if (hasChildContent(childEntry)) { + freeChildContent(childEntry); + } + } else { + if (!hasChildContent(childEntry)) { + bindChildContent(childEntry); + } + } + } + } + } + + private boolean hasChildContent(NotificationEntry entry) { + ExpandableNotificationRow row = entry.getRow(); + return row.getPrivateLayout().getContractedChild() != null + || row.getPrivateLayout().getExpandedChild() != null; + } + + private void freeChildContent(NotificationEntry entry) { + RowContentBindParams params = mStage.getStageParams(entry); + params.freeContentViews(FLAG_CONTENT_VIEW_CONTRACTED); + params.freeContentViews(FLAG_CONTENT_VIEW_EXPANDED); + mStage.requestRebind(entry, null); + } + + private void bindChildContent(NotificationEntry entry) { + RowContentBindParams params = mStage.getStageParams(entry); + params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED); + params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED); + mStage.requestRebind(entry, null); + } + + /** + * How big the buffer of extra views we keep around to be ready to show when we do need to + * dynamically inflate. + */ + private static final int EXTRA_VIEW_BUFFER_COUNT = 1; + + private static final int CHILD_BIND_CUTOFF = + NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED + EXTRA_VIEW_BUFFER_COUNT; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java index 07cf9d9051c4..df21f0b21ec1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java @@ -77,7 +77,8 @@ public class NotificationAlertingManager { public void onEntryRemoved( NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { stopAlerting(entry.getKey()); } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java index 25253a15b125..2beceb2c5e0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java @@ -92,7 +92,8 @@ public interface NotificationEntryListener { default void onEntryRemoved( NotificationEntry entry, @Nullable NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 5ebd368a7173..7f0479c39c95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -477,7 +477,7 @@ public class NotificationEntryManager implements mLogger.logNotifRemoved(entry.getKey(), removedByUser); for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryRemoved(entry, visibility, removedByUser); + listener.onEntryRemoved(entry, visibility, removedByUser, reason); } for (NotifCollectionListener listener : mNotifCollectionListeners) { // NEM doesn't have a good knowledge of reasons so defaulting to unknown. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java index f2765db6fd46..c9c6f28b5b27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java @@ -59,7 +59,8 @@ public class NotificationListController { public void onEntryRemoved( NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { mListContainer.cleanUpViewStateForEntry(entry); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 25a832d8da5e..3e9d8a436f38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -153,6 +153,7 @@ public final class NotificationEntry extends ListEntry { public String remoteInputMimeType; public Uri remoteInputUri; private Notification.BubbleMetadata mBubbleMetadata; + private ShortcutInfo mShortcutInfo; /** * If {@link android.app.RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index d0b553db2100..c9ebc3597baf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -43,6 +43,8 @@ import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl; import com.android.systemui.statusbar.notification.init.NotificationsControllerStub; import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger; +import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -144,13 +146,22 @@ public interface NotificationsModule { @UiBackground Executor uiBgExecutor, NotificationEntryManager entryManager, StatusBarStateController statusBarStateController, - NotificationLogger.ExpansionStateLogger expansionStateLogger) { + NotificationLogger.ExpansionStateLogger expansionStateLogger, + NotificationPanelLogger notificationPanelLogger) { return new NotificationLogger( notificationListener, uiBgExecutor, entryManager, statusBarStateController, - expansionStateLogger); + expansionStateLogger, + notificationPanelLogger); + } + + /** Provides an instance of {@link NotificationPanelLogger} */ + @Singleton + @Provides + static NotificationPanelLogger provideNotificationPanelLogger() { + return new NotificationPanelLoggerImpl(); } /** Provides an instance of {@link NotificationBlockingHelperManager} */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java index becb758bf470..a088d85b2288 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java @@ -70,6 +70,7 @@ public class NotificationLogger implements StateListener { private final NotificationListenerService mNotificationListener; private final Executor mUiBgExecutor; private final NotificationEntryManager mEntryManager; + private final NotificationPanelLogger mNotificationPanelLogger; private HeadsUpManager mHeadsUpManager; private final ExpansionStateLogger mExpansionStateLogger; @@ -198,13 +199,15 @@ public class NotificationLogger implements StateListener { @UiBackground Executor uiBgExecutor, NotificationEntryManager entryManager, StatusBarStateController statusBarStateController, - ExpansionStateLogger expansionStateLogger) { + ExpansionStateLogger expansionStateLogger, + NotificationPanelLogger notificationPanelLogger) { mNotificationListener = notificationListener; mUiBgExecutor = uiBgExecutor; mEntryManager = entryManager; mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mExpansionStateLogger = expansionStateLogger; + mNotificationPanelLogger = notificationPanelLogger; // Not expected to be destroyed, don't need to unsubscribe statusBarStateController.addCallback(this); @@ -213,7 +216,8 @@ public class NotificationLogger implements StateListener { public void onEntryRemoved( NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { if (removedByUser && visibility != null) { logNotificationClear(entry.getKey(), entry.getSbn(), visibility); } @@ -263,6 +267,9 @@ public class NotificationLogger implements StateListener { // (Note that in cases where the scroller does emit events, this // additional event doesn't break anything.) mNotificationLocationsChangedListener.onChildLocationsChanged(); + // TODO - determine if this work needs to be put on mUiBgExecutor + mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(), + mEntryManager.getVisibleNotifications()); } private void setDozing(boolean dozing) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java new file mode 100644 index 000000000000..0d0bc981382e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java @@ -0,0 +1,91 @@ +/* + * 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.systemui.statusbar.notification.logging; + +import android.annotation.Nullable; +import android.service.notification.StatusBarNotification; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import java.util.List; + +import nano.Notifications; + +/** + * Statsd logging for notification panel. + */ +public interface NotificationPanelLogger { + + /** + * Log a NOTIFICATION_PANEL_REPORTED statsd event. + * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications() + */ + void logPanelShown(boolean isLockscreen, + @Nullable List<NotificationEntry> visibleNotifications); + + enum NotificationPanelEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "Notification panel shown from status bar.") + NOTIFICATION_PANEL_OPEN_STATUS_BAR(200), + @UiEvent(doc = "Notification panel shown from lockscreen.") + NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201); + + private final int mId; + NotificationPanelEvent(int id) { + mId = id; + } + @Override public int getId() { + return mId; + } + + public static NotificationPanelEvent fromLockscreen(boolean isLockscreen) { + return isLockscreen ? NOTIFICATION_PANEL_OPEN_LOCKSCREEN : + NOTIFICATION_PANEL_OPEN_STATUS_BAR; + } + } + + /** + * Composes a NotificationsList proto from the list of visible notifications. + * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications() + * @return NotificationList proto suitable for SysUiStatsLog.write(NOTIFICATION_PANEL_REPORTED) + */ + static Notifications.NotificationList toNotificationProto( + @Nullable List<NotificationEntry> visibleNotifications) { + Notifications.NotificationList notificationList = new Notifications.NotificationList(); + if (visibleNotifications == null) { + return notificationList; + } + final Notifications.Notification[] nn = + new Notifications.Notification[visibleNotifications.size()]; + int i = 0; + for (NotificationEntry ne : visibleNotifications) { + StatusBarNotification n = ne.getSbn(); + Notifications.Notification np = new Notifications.Notification(); + np.uid = n.getUid(); + np.packageName = n.getPackageName(); + np.instanceId = n.getInstanceId().getId(); + // TODO set np.groupInstanceId + np.isGroupSummary = n.getNotification().isGroupSummary(); + np.section = 1 + ne.getBucket(); // We want 0 to mean not set / unknown + nn[i] = np; + ++i; + } + notificationList.notifications = nn; + return notificationList; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java new file mode 100644 index 000000000000..0df426a4aafe --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java @@ -0,0 +1,42 @@ +/* + * 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.systemui.statusbar.notification.logging; + +import com.android.systemui.shared.system.SysUiStatsLog; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import com.google.protobuf.nano.MessageNano; + +import java.util.List; + +import nano.Notifications; + +/** + * Normal implementation of NotificationPanelLogger. + */ +public class NotificationPanelLoggerImpl implements NotificationPanelLogger { + @Override + public void logPanelShown(boolean isLockscreen, + List<NotificationEntry> visibleNotifications) { + final Notifications.NotificationList proto = NotificationPanelLogger.toNotificationProto( + visibleNotifications); + SysUiStatsLog.write(SysUiStatsLog.NOTIFICATION_PANEL_REPORTED, + /* int event_id */ NotificationPanelEvent.fromLockscreen(isLockscreen).getId(), + /* int num_notifications*/ proto.notifications.length, + /* byte[] notifications*/ MessageNano.toByteArray(proto)); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto new file mode 100644 index 000000000000..94a7fcb47670 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** + * NotificationList proto from atoms.proto, duplicated here so that it's accessible in the build. + * Must be kept in sync with the version in atoms.proto. + */ + +message Notification { + // The notifying app's uid and package. + optional int32 uid = 1; + optional string package_name = 2; + // A small system-assigned identifier for the notification. + optional int32 instance_id = 3; + + // Grouping information. + optional int32 group_instance_id = 4; + optional bool is_group_summary = 5; + + // The section of the shade that the notification is in. + // See NotificationSectionsManager.PriorityBucket. + enum NotificationSection { + SECTION_UNKNOWN = 0; + SECTION_PEOPLE = 1; + SECTION_ALERTING = 2; + SECTION_SILENT = 3; + } + optional NotificationSection section = 6; +} + +message NotificationList { + repeated Notification notifications = 1; // An ordered sequence of notifications. +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt index 2a02c199ee5c..3007198ff756 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt @@ -47,7 +47,7 @@ data class PersonModel( val key: PersonKey, val name: CharSequence, val avatar: Drawable, - val clickIntent: PendingIntent, + val clickRunnable: Runnable, val userId: Int ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt index 721f32a7ed15..360bf96a3cce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt @@ -17,20 +17,30 @@ package com.android.systemui.statusbar.notification.people import android.app.Notification +import android.content.Context +import android.content.pm.LauncherApps +import android.content.pm.PackageManager +import android.content.pm.ShortcutInfo import android.content.pm.UserInfo +import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.os.UserManager +import android.service.notification.NotificationListenerService +import android.service.notification.NotificationListenerService.REASON_SNOOZED import android.service.notification.StatusBarNotification +import android.util.IconDrawableFactory import android.util.SparseArray import android.view.View import android.view.ViewGroup import android.widget.ImageView import com.android.internal.statusbar.NotificationVisibility import com.android.internal.widget.MessagingGroup +import com.android.settingslib.notification.ConversationIconFactory import com.android.systemui.R import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.NotificationPersonExtractorPlugin +import com.android.systemui.statusbar.NotificationListener import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.notification.NotificationEntryListener import com.android.systemui.statusbar.notification.NotificationEntryManager @@ -69,7 +79,7 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor( override fun extractPerson(sbn: StatusBarNotification) = plugin?.extractPerson(sbn)?.run { - PersonModel(key, name, avatar, clickIntent, sbn.user.identifier) + PersonModel(key, name, avatar, clickRunnable, sbn.user.identifier) } override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn) @@ -80,17 +90,26 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor( @Singleton class PeopleHubDataSourceImpl @Inject constructor( - private val notificationEntryManager: NotificationEntryManager, - private val extractor: NotificationPersonExtractor, - private val userManager: UserManager, - @Background private val bgExecutor: Executor, - @Main private val mainExecutor: Executor, - private val notifLockscreenUserMgr: NotificationLockscreenUserManager -) : DataSource<PeopleHubModel> { + private val notificationEntryManager: NotificationEntryManager, + private val extractor: NotificationPersonExtractor, + private val userManager: UserManager, + private val launcherApps: LauncherApps, + private val packageManager: PackageManager, + private val c: Context, + private val notificationListener: NotificationListener, + @Background private val bgExecutor: Executor, + @Main private val mainExecutor: Executor, + private val notifLockscreenUserMgr: NotificationLockscreenUserManager, + private val peopleNotificationIdentifier: PeopleNotificationIdentifier + ) : DataSource<PeopleHubModel> { private var userChangeSubscription: Subscription? = null private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>() private val peopleHubManagerForUser = SparseArray<PeopleHubManager>() + val context: Context = c.applicationContext + val iconFactory = ConversationIconFactory(context, launcherApps, packageManager, + IconDrawableFactory.newInstance(context), context.resources.getDimensionPixelSize( + R.dimen.notification_guts_conversation_icon_size)) private val notificationEntryListener = object : NotificationEntryListener { override fun onEntryInflated(entry: NotificationEntry) = addVisibleEntry(entry) @@ -102,18 +121,23 @@ class PeopleHubDataSourceImpl @Inject constructor( override fun onEntryRemoved( entry: NotificationEntry, visibility: NotificationVisibility?, - removedByUser: Boolean - ) = removeVisibleEntry(entry) + removedByUser: Boolean, + reason: Int + ) = removeVisibleEntry(entry, reason) } - private fun removeVisibleEntry(entry: NotificationEntry) { + private fun removeVisibleEntry(entry: NotificationEntry, reason: Int) { (extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey())?.let { key -> val userId = entry.sbn.user.identifier bgExecutor.execute { val parentId = userManager.getProfileParent(userId)?.id ?: userId mainExecutor.execute { - if (peopleHubManagerForUser[parentId]?.removeActivePerson(key) == true) { - updateUi() + if (reason == REASON_SNOOZED) { + if (peopleHubManagerForUser[parentId]?.migrateActivePerson(key) == true) { + updateUi() + } + } else { + peopleHubManagerForUser[parentId]?.removeActivePerson(key) } } } @@ -121,7 +145,7 @@ class PeopleHubDataSourceImpl @Inject constructor( } private fun addVisibleEntry(entry: NotificationEntry) { - (extractor.extractPerson(entry.sbn) ?: entry.extractPerson())?.let { personModel -> + entry.extractPerson()?.let { personModel -> val userId = entry.sbn.user.identifier bgExecutor.execute { val parentId = userManager.getProfileParent(userId)?.id ?: userId @@ -180,6 +204,34 @@ class PeopleHubDataSourceImpl @Inject constructor( listener.onDataChanged(model) } } + + private fun NotificationEntry.extractPerson(): PersonModel? { + if (!peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) { + return null + } + val clickRunnable = Runnable { notificationListener.unsnoozeNotification(key) } + val extras = sbn.notification.extras + val name = ranking.shortcutInfo?.shortLabel + ?: extras.getString(Notification.EXTRA_CONVERSATION_TITLE) + ?: extras.getString(Notification.EXTRA_TITLE) + ?: return null + val drawable = ranking.shortcutInfo?.getIcon(iconFactory, sbn, ranking) + ?: iconFactory.getConversationDrawable(extractAvatarFromRow(this), sbn.packageName, + sbn.uid, ranking.channel.isImportantConversation) + + return PersonModel(key, name, drawable, clickRunnable, sbn.user.identifier) + } + + private fun ShortcutInfo.getIcon(iconFactory: ConversationIconFactory, + sbn: StatusBarNotification, + ranking: NotificationListenerService.Ranking): Drawable? { + return iconFactory.getConversationDrawable(ranking.shortcutInfo, sbn.packageName, sbn.uid, + ranking.channel.isImportantConversation) + } + + private fun NotificationEntry.extractPersonKey(): PersonKey? = + // TODO migrate to shortcut id when snoozing is conversation wide + if (peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) key else null } private fun NotificationLockscreenUserManager.registerListener( @@ -201,7 +253,7 @@ class PeopleHubManager { // People that were once "active" and have been dismissed, and so can be displayed in the hub private val inactivePeople = ArrayDeque<PersonModel>(MAX_STORED_INACTIVE_PEOPLE) - fun removeActivePerson(key: PersonKey): Boolean { + fun migrateActivePerson(key: PersonKey): Boolean { activePeople.remove(key)?.let { data -> if (inactivePeople.size >= MAX_STORED_INACTIVE_PEOPLE) { inactivePeople.removeLast() @@ -212,6 +264,10 @@ class PeopleHubManager { return false } + fun removeActivePerson(key: PersonKey) { + activePeople.remove(key) + } + fun addActivePerson(person: PersonModel): Boolean { activePeople[person.key] = person return inactivePeople.removeIf { it.key == person.key } @@ -229,19 +285,6 @@ private val ViewGroup.children private fun ViewGroup.childrenWithId(id: Int): Sequence<View> = children.filter { it.id == id } -private fun NotificationEntry.extractPerson(): PersonModel? { - if (!isMessagingNotification()) { - return null - } - val clickIntent = sbn.notification.contentIntent ?: return null - val extras = sbn.notification.extras - val name = extras.getString(Notification.EXTRA_CONVERSATION_TITLE) - ?: extras.getString(Notification.EXTRA_TITLE) - ?: return null - val drawable = extractAvatarFromRow(this) ?: return null - return PersonModel(key, name, drawable, clickIntent, sbn.user.identifier) -} - fun extractAvatarFromRow(entry: NotificationEntry): Drawable? = entry.row ?.childrenWithId(R.id.expanded) @@ -261,8 +304,3 @@ fun extractAvatarFromRow(entry: NotificationEntry): Drawable? = } ?.firstOrNull() -private fun NotificationEntry.extractPersonKey(): PersonKey? = - if (isMessagingNotification()) key else null - -private fun NotificationEntry.isMessagingNotification() = - sbn.notification.notificationStyle == Notification.MessagingStyle::class.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt index a58c42b839cf..62d3612a483b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt @@ -102,30 +102,19 @@ private class PeopleHubDataListenerImpl( @Singleton class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor( private val activityStarter: ActivityStarter, - private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel>, - private val settingChangeSource: DataSource<@JvmSuppressWildcards Boolean> + private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel> ) : DataSource<PeopleHubViewModelFactory> { override fun registerListener(listener: DataListener<PeopleHubViewModelFactory>): Subscription { - var stripEnabled = false var model: PeopleHubModel? = null fun updateListener() { // don't invoke listener until we've received our first model model?.let { model -> - val factory = - if (stripEnabled) PeopleHubViewModelFactoryImpl(model, activityStarter) - else EmptyViewModelFactory + val factory = PeopleHubViewModelFactoryImpl(model, activityStarter) listener.onDataChanged(factory) } } - - val settingSub = settingChangeSource.registerListener(object : DataListener<Boolean> { - override fun onDataChanged(data: Boolean) { - stripEnabled = data - updateListener() - } - }) val dataSub = dataSource.registerListener(object : DataListener<PeopleHubModel> { override fun onDataChanged(data: PeopleHubModel) { model = data @@ -134,7 +123,6 @@ class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor( }) return object : Subscription { override fun unsubscribe() { - settingSub.unsubscribe() dataSub.unsubscribe() } } @@ -155,11 +143,7 @@ private class PeopleHubViewModelFactoryImpl( override fun createWithAssociatedClickView(view: View): PeopleHubViewModel { val personViewModels = model.people.asSequence().map { personModel -> val onClick = { - activityStarter.startPendingIntentDismissingKeyguard( - personModel.clickIntent, - null, - view - ) + personModel.clickRunnable.run() } PersonViewModel(personModel.name, personModel.avatar, onClick) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 97755fcb8ea9..6d3f1267b38b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -18,7 +18,10 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC; @@ -467,6 +470,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } }; switch (inflationFlag) { + case FLAG_CONTENT_VIEW_CONTRACTED: + getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_CONTRACTED, + freeViewRunnable); + break; + case FLAG_CONTENT_VIEW_EXPANDED: + getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_EXPANDED, + freeViewRunnable); + break; case FLAG_CONTENT_VIEW_HEADS_UP: getPrivateLayout().performWhenContentInactive(VISIBLE_TYPE_HEADSUP, freeViewRunnable); @@ -807,7 +818,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // TODO: Move inflation logic out of this call if (mIsChildInGroup != isChildInGroup) { mIsChildInGroup = isChildInGroup; - if (mIsLowPriority) { + if (!isRemoved() && mIsLowPriority) { RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry); params.setUseLowPriority(mIsLowPriority); mRowContentBindStage.requestRebind(mEntry, null /* callback */); @@ -1576,13 +1587,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // TODO: Move inflation logic out of this call and remove this method if (mNeedsRedaction != needsRedaction) { mNeedsRedaction = needsRedaction; - RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry); - if (needsRedaction) { - params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC); - } else { - params.freeContentViews(FLAG_CONTENT_VIEW_PUBLIC); + if (!isRemoved()) { + RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry); + if (needsRedaction) { + params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC); + } else { + params.freeContentViews(FLAG_CONTENT_VIEW_PUBLIC); + } + mRowContentBindStage.requestRebind(mEntry, null /* callback */); } - mRowContentBindStage.requestRebind(mEntry, null /* callback */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index e3ca283d13ad..6dd4ff9235c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; import android.annotation.NonNull; @@ -191,6 +192,18 @@ public class NotificationContentInflater implements NotificationRowContentBinder private void freeNotificationView(NotificationEntry entry, ExpandableNotificationRow row, @InflationFlag int inflateFlag) { switch (inflateFlag) { + case FLAG_CONTENT_VIEW_CONTRACTED: + if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_CONTRACTED)) { + row.getPrivateLayout().setContractedChild(null); + mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_CONTRACTED); + } + break; + case FLAG_CONTENT_VIEW_EXPANDED: + if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_EXPANDED)) { + row.getPrivateLayout().setExpandedChild(null); + mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_EXPANDED); + } + break; case FLAG_CONTENT_VIEW_HEADS_UP: if (row.getPrivateLayout().isContentViewInactive(VISIBLE_TYPE_HEADSUP)) { row.getPrivateLayout().setHeadsUpChild(null); @@ -204,8 +217,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder mRemoteViewCache.removeCachedView(entry, FLAG_CONTENT_VIEW_PUBLIC); } break; - case FLAG_CONTENT_VIEW_CONTRACTED: - case FLAG_CONTENT_VIEW_EXPANDED: default: break; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index d1b9a87c1ddc..27fd1b2c5aed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -71,7 +71,13 @@ public class NotificationContentView extends FrameLayout { public static final int VISIBLE_TYPE_EXPANDED = 1; public static final int VISIBLE_TYPE_HEADSUP = 2; private static final int VISIBLE_TYPE_SINGLELINE = 3; - public static final int UNDEFINED = -1; + /** + * Used when there is no content on the view such as when we're a public layout but don't + * need to show. + */ + private static final int VISIBLE_TYPE_NONE = -1; + + private static final int UNDEFINED = -1; private final Rect mClipBounds = new Rect(); @@ -99,7 +105,7 @@ public class NotificationContentView extends FrameLayout { private HybridGroupManager mHybridGroupManager; private int mClipTopAmount; private int mContentHeight; - private int mVisibleType = VISIBLE_TYPE_CONTRACTED; + private int mVisibleType = VISIBLE_TYPE_NONE; private boolean mAnimate; private boolean mIsHeadsUp; private boolean mLegacy; @@ -141,7 +147,7 @@ public class NotificationContentView extends FrameLayout { /** The visible type at the start of a touch driven transformation */ private int mTransformationStartVisibleType; /** The visible type at the start of an animation driven transformation */ - private int mAnimationStartVisibleType = UNDEFINED; + private int mAnimationStartVisibleType = VISIBLE_TYPE_NONE; private boolean mUserExpanding; private int mSingleLineWidthIndention; private boolean mForceSelectNextLayout = true; @@ -386,7 +392,7 @@ public class NotificationContentView extends FrameLayout { mContractedChild = null; mContractedWrapper = null; if (mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED) { - mTransformationStartVisibleType = UNDEFINED; + mTransformationStartVisibleType = VISIBLE_TYPE_NONE; } return; } @@ -434,7 +440,7 @@ public class NotificationContentView extends FrameLayout { mExpandedChild = null; mExpandedWrapper = null; if (mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED) { - mTransformationStartVisibleType = UNDEFINED; + mTransformationStartVisibleType = VISIBLE_TYPE_NONE; } if (mVisibleType == VISIBLE_TYPE_EXPANDED) { selectLayout(false /* animate */, true /* force */); @@ -472,7 +478,7 @@ public class NotificationContentView extends FrameLayout { mHeadsUpChild = null; mHeadsUpWrapper = null; if (mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP) { - mTransformationStartVisibleType = UNDEFINED; + mTransformationStartVisibleType = VISIBLE_TYPE_NONE; } if (mVisibleType == VISIBLE_TYPE_HEADSUP) { selectLayout(false /* animate */, true /* force */); @@ -597,7 +603,7 @@ public class NotificationContentView extends FrameLayout { } // Size change of the expanded version - if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart >= 0 + if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart != UNDEFINED && mExpandedChild != null) { return Math.min(mContentHeightAtAnimationStart, getViewHeight(VISIBLE_TYPE_EXPANDED)); } @@ -607,10 +613,12 @@ public class NotificationContentView extends FrameLayout { hint = getViewHeight(VISIBLE_TYPE_HEADSUP); } else if (mExpandedChild != null) { hint = getViewHeight(VISIBLE_TYPE_EXPANDED); - } else { + } else if (mContractedChild != null) { hint = getViewHeight(VISIBLE_TYPE_CONTRACTED) + mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_action_list_height); + } else { + hint = getMinHeight(); } if (mExpandedChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_EXPANDED)) { @@ -646,7 +654,7 @@ public class NotificationContentView extends FrameLayout { if (mForceSelectNextLayout) { forceUpdateVisibilities(); } - if (mTransformationStartVisibleType != UNDEFINED + if (mTransformationStartVisibleType != VISIBLE_TYPE_NONE && mVisibleType != mTransformationStartVisibleType && getViewForVisibleType(mTransformationStartVisibleType) != null) { final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType); @@ -823,7 +831,7 @@ public class NotificationContentView extends FrameLayout { fireExpandedVisibleListenerIfVisible(); // forceUpdateVisibilities cancels outstanding animations without updating the // mAnimationStartVisibleType. Do so here instead. - mAnimationStartVisibleType = UNDEFINED; + mAnimationStartVisibleType = VISIBLE_TYPE_NONE; } private void fireExpandedVisibleListenerIfVisible() { @@ -898,7 +906,7 @@ public class NotificationContentView extends FrameLayout { fireExpandedVisibleListenerIfVisible(); // updateViewVisibilities cancels outstanding animations without updating the // mAnimationStartVisibleType. Do so here instead. - mAnimationStartVisibleType = UNDEFINED; + mAnimationStartVisibleType = VISIBLE_TYPE_NONE; } private void updateViewVisibility(int visibleType, int type, View view, @@ -924,7 +932,7 @@ public class NotificationContentView extends FrameLayout { if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) { hiddenView.setVisible(false); } - mAnimationStartVisibleType = UNDEFINED; + mAnimationStartVisibleType = VISIBLE_TYPE_NONE; } }); fireExpandedVisibleListenerIfVisible(); @@ -1041,8 +1049,10 @@ public class NotificationContentView extends FrameLayout { && (!mIsChildInGroup || isGroupExpanded() || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) { return VISIBLE_TYPE_CONTRACTED; - } else { + } else if (!noExpandedChild) { return VISIBLE_TYPE_EXPANDED; + } else { + return VISIBLE_TYPE_NONE; } } } @@ -1423,7 +1433,8 @@ public class NotificationContentView extends FrameLayout { if (mExpandedChild != null && mExpandedChild.getHeight() != 0) { if ((!mIsHeadsUp && !mHeadsUpAnimatingAway) || mHeadsUpChild == null || !mContainingNotification.canShowHeadsUp()) { - if (mExpandedChild.getHeight() <= mContractedChild.getHeight()) { + if (mContractedChild == null + || mExpandedChild.getHeight() <= mContractedChild.getHeight()) { expandable = false; } } else if (mExpandedChild.getHeight() <= mHeadsUpChild.getHeight()) { @@ -1514,7 +1525,7 @@ public class NotificationContentView extends FrameLayout { if (userExpanding) { mTransformationStartVisibleType = mVisibleType; } else { - mTransformationStartVisibleType = UNDEFINED; + mTransformationStartVisibleType = VISIBLE_TYPE_NONE; mVisibleType = calculateVisibleType(); updateViewVisibilities(mVisibleType); updateBackgroundColor(false); @@ -1558,6 +1569,7 @@ public class NotificationContentView extends FrameLayout { } public void setContentHeightAnimating(boolean animating) { + //TODO: It's odd that this does nothing when animating is true if (!animating) { mContentHeightAtAnimationStart = UNDEFINED; } @@ -1565,7 +1577,7 @@ public class NotificationContentView extends FrameLayout { @VisibleForTesting boolean isAnimatingVisibleType() { - return mAnimationStartVisibleType != UNDEFINED; + return mAnimationStartVisibleType != VISIBLE_TYPE_NONE; } public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { @@ -1758,17 +1770,25 @@ public class NotificationContentView extends FrameLayout { } public int getExpandHeight() { - int viewType = VISIBLE_TYPE_EXPANDED; - if (mExpandedChild == null) { + int viewType; + if (mExpandedChild != null) { + viewType = VISIBLE_TYPE_EXPANDED; + } else if (mContractedChild != null) { viewType = VISIBLE_TYPE_CONTRACTED; + } else { + return getMinHeight(); } return getViewHeight(viewType) + getExtraRemoteInputHeight(mExpandedRemoteInput); } public int getHeadsUpHeight(boolean forceNoHeader) { - int viewType = VISIBLE_TYPE_HEADSUP; - if (mHeadsUpChild == null) { + int viewType; + if (mHeadsUpChild != null) { + viewType = VISIBLE_TYPE_HEADSUP; + } else if (mContractedChild != null) { viewType = VISIBLE_TYPE_CONTRACTED; + } else { + return getMinHeight(); } // The headsUp remote input quickly switches to the expanded one, so lets also include that // one diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index 60eda06dd3f9..1088cdc30f37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -20,6 +20,7 @@ import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; @@ -215,15 +216,7 @@ public class NotificationConversationInfo extends LinearLayout implements if (TextUtils.isEmpty(mConversationId)) { throw new IllegalArgumentException("Does not have required information"); } - // TODO: consider querying this earlier in the notification pipeline and passing it in - LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() - .setPackage(mPackageName) - .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) - .setShortcutIds(Arrays.asList(mConversationId)); - List<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser()); - if (shortcuts != null && !shortcuts.isEmpty()) { - mShortcutInfo = shortcuts.get(0); - } + mShortcutInfo = entry.getRanking().getShortcutInfo(); mIsBubbleable = mEntry.getBubbleMetadata() != null && Settings.Global.getInt(mContext.getContentResolver(), @@ -324,8 +317,9 @@ public class NotificationConversationInfo extends LinearLayout implements private void bindIcon() { ImageView image = findViewById(R.id.conversation_icon); if (mShortcutInfo != null) { - image.setImageBitmap(mIconFactory.getConversationBitmap( - mShortcutInfo, mPackageName, mAppUid)); + image.setImageDrawable(mIconFactory.getConversationDrawable( + mShortcutInfo, mPackageName, mAppUid, + mNotificationChannel.isImportantConversation())); } else { if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) { // TODO: maybe use a generic group icon, or a composite of recent senders @@ -479,6 +473,9 @@ public class NotificationConversationInfo extends LinearLayout implements mContext.getString(R.string.notification_conversation_mute)); mute.setImageResource(R.drawable.ic_notifications_silence); } + + // update icon in case importance has changed + bindIcon(); } private void updateChannel() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index c01f6c4ef0d2..d746822ddcff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -390,7 +390,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx }; } ConversationIconFactory iconFactoryLoader = new ConversationIconFactory(mContext, - launcherApps, pmUser, IconDrawableFactory.newInstance(mContext), + launcherApps, pmUser, IconDrawableFactory.newInstance(mContext, false), mContext.getResources().getDimensionPixelSize( R.dimen.notification_guts_conversation_icon_size)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 75ceb0fa1989..d7c88e3a3f60 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -53,8 +53,7 @@ public class NotificationChildrenContainer extends ViewGroup { static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2; @VisibleForTesting static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5; - @VisibleForTesting - static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8; + public static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8; private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() { private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java index b3561c2deda7..8ee2f5002f0d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; + import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; @@ -100,14 +102,11 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section private boolean mInitialized = false; private SectionHeaderView mGentleHeader; - private boolean mGentleHeaderVisible; @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener; private SectionHeaderView mAlertingHeader; - private boolean mAlertingHeaderVisible; private PeopleHubView mPeopleHubView; - private boolean mPeopleHeaderVisible; private boolean mPeopleHubVisible = false; @Nullable private Subscription mPeopleHubSubscription; @@ -231,88 +230,135 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section return; } + // The overall strategy here is to iterate over the current children of mParent, looking + // for where the sections headers are currently positioned, and where each section begins. + // Then, once we find the start of a new section, we track that position as the "target" for + // the section header, adjusted for the case where existing headers are in front of that + // target, but won't be once they are moved / removed after the pass has completed. + final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD; final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled(); boolean peopleNotifsPresent = false; + + int currentPeopleHeaderIdx = -1; int peopleHeaderTarget = -1; + int currentAlertingHeaderIdx = -1; int alertingHeaderTarget = -1; + int currentGentleHeaderIdx = -1; int gentleHeaderTarget = -1; - int viewCount = 0; + int lastNotifIndex = 0; - if (showHeaders) { - final int childCount = mParent.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = mParent.getChildAt(i); - if (child.getVisibility() == View.GONE - || !(child instanceof ExpandableNotificationRow)) { - continue; - } - ExpandableNotificationRow row = (ExpandableNotificationRow) child; - switch (row.getEntry().getBucket()) { - case BUCKET_PEOPLE: - if (peopleHeaderTarget == -1) { - peopleNotifsPresent = true; - peopleHeaderTarget = viewCount; - viewCount++; + final int childCount = mParent.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = mParent.getChildAt(i); + + // Track the existing positions of the headers + if (child == mPeopleHubView) { + currentPeopleHeaderIdx = i; + continue; + } + if (child == mAlertingHeader) { + currentAlertingHeaderIdx = i; + continue; + } + if (child == mGentleHeader) { + currentGentleHeaderIdx = i; + continue; + } + + if (!(child instanceof ExpandableNotificationRow)) { + continue; + } + lastNotifIndex = i; + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + // Once we enter a new section, calculate the target position for the header. + switch (row.getEntry().getBucket()) { + case BUCKET_HEADS_UP: + break; + case BUCKET_PEOPLE: + peopleNotifsPresent = true; + if (showHeaders && peopleHeaderTarget == -1) { + peopleHeaderTarget = i; + // Offset the target if there are other headers before this that will be + // moved. + if (currentPeopleHeaderIdx != -1) { + peopleHeaderTarget--; } - break; - case BUCKET_ALERTING: - if (usingPeopleFiltering && alertingHeaderTarget == -1) { - alertingHeaderTarget = viewCount; - viewCount++; + if (currentAlertingHeaderIdx != -1) { + peopleHeaderTarget--; } - break; - case BUCKET_SILENT: - if (gentleHeaderTarget == -1) { - gentleHeaderTarget = viewCount; - viewCount++; + if (currentGentleHeaderIdx != -1) { + peopleHeaderTarget--; } - break; - } - viewCount++; + } + break; + case BUCKET_ALERTING: + if (showHeaders && usingPeopleFiltering && alertingHeaderTarget == -1) { + alertingHeaderTarget = i; + // Offset the target if there are other headers before this that will be + // moved. + if (currentAlertingHeaderIdx != -1) { + alertingHeaderTarget--; + } + if (currentGentleHeaderIdx != -1) { + alertingHeaderTarget--; + } + } + break; + case BUCKET_SILENT: + if (showHeaders && gentleHeaderTarget == -1) { + gentleHeaderTarget = i; + // Offset the target if there are other headers before this that will be + // moved. + if (currentGentleHeaderIdx != -1) { + gentleHeaderTarget--; + } + } + break; + default: + throw new IllegalStateException("Cannot find section bucket for view"); } - if (usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) { - // Insert the people header even if there are no people visible, in order to show - // the hub. Put it directly above the next header. - if (alertingHeaderTarget != -1) { - peopleHeaderTarget = alertingHeaderTarget; - alertingHeaderTarget++; - gentleHeaderTarget++; - } else if (gentleHeaderTarget != -1) { - peopleHeaderTarget = gentleHeaderTarget; - gentleHeaderTarget++; - } else { - // Put it at the end of the list. - peopleHeaderTarget = viewCount; - } + } + if (showHeaders && usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) { + // Insert the people header even if there are no people visible, in order to show + // the hub. Put it directly above the next header. + if (alertingHeaderTarget != -1) { + peopleHeaderTarget = alertingHeaderTarget; + } else if (gentleHeaderTarget != -1) { + peopleHeaderTarget = gentleHeaderTarget; + } else { + // Put it at the end of the list. + peopleHeaderTarget = lastNotifIndex; } } - // Allow swiping the people header if the section is empty - mPeopleHubView.setCanSwipe(mPeopleHubVisible && !peopleNotifsPresent); - - mPeopleHeaderVisible = adjustHeaderVisibilityAndPosition( - peopleHeaderTarget, mPeopleHubView, mPeopleHeaderVisible); - mAlertingHeaderVisible = adjustHeaderVisibilityAndPosition( - alertingHeaderTarget, mAlertingHeader, mAlertingHeaderVisible); - mGentleHeaderVisible = adjustHeaderVisibilityAndPosition( - gentleHeaderTarget, mGentleHeader, mGentleHeaderVisible); + // Add headers in reverse order to preserve indices + adjustHeaderVisibilityAndPosition( + gentleHeaderTarget, mGentleHeader, currentGentleHeaderIdx); + adjustHeaderVisibilityAndPosition( + alertingHeaderTarget, mAlertingHeader, currentAlertingHeaderIdx); + adjustHeaderVisibilityAndPosition( + peopleHeaderTarget, mPeopleHubView, currentPeopleHeaderIdx); + + // Update headers to reflect state of section contents + mGentleHeader.setAreThereDismissableGentleNotifs( + mParent.hasActiveClearableNotifications(ROWS_GENTLE)); + mPeopleHubView.setCanSwipe(showHeaders && mPeopleHubVisible && !peopleNotifsPresent); + if (peopleHeaderTarget != currentPeopleHeaderIdx) { + mPeopleHubView.resetTranslation(); + } } - private boolean adjustHeaderVisibilityAndPosition( - int targetIndex, StackScrollerDecorView header, boolean isCurrentlyVisible) { - if (targetIndex == -1) { - if (isCurrentlyVisible) { + private void adjustHeaderVisibilityAndPosition( + int targetPosition, StackScrollerDecorView header, int currentPosition) { + if (targetPosition == -1) { + if (currentPosition != -1) { mParent.removeView(header); } - return false; } else { - if (header instanceof SwipeableView) { - ((SwipeableView) header).resetTranslation(); - } - if (!isCurrentlyVisible) { + if (currentPosition == -1) { // If the header is animating away, it will still have a parent, so detach it first // TODO: We should really cancel the active animations here. This will happen // automatically when the view's intro animation starts, but it's a fragile link. @@ -321,11 +367,10 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section header.setTransientContainer(null); } header.setContentVisible(true); - mParent.addView(header, targetIndex); - } else if (mParent.indexOfChild(header) != targetIndex) { - mParent.changeViewPosition(header, targetIndex); + mParent.addView(header, targetPosition); + } else { + mParent.changeViewPosition(header, targetPosition); } - return true; } } @@ -400,10 +445,20 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section @VisibleForTesting - SectionHeaderView getGentleHeaderView() { + ExpandableView getGentleHeaderView() { return mGentleHeader; } + @VisibleForTesting + ExpandableView getAlertingHeaderView() { + return mAlertingHeader; + } + + @VisibleForTesting + ExpandableView getPeopleHeaderView() { + return mPeopleHubView; + } + private final ConfigurationListener mConfigurationListener = new ConfigurationListener() { @Override public void onLocaleListChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index 971f045e3fb4..c05119de1e79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -19,56 +19,64 @@ package com.android.systemui.statusbar.phone; import android.content.Context; import android.os.Handler; import android.os.RemoteException; +import android.util.ArraySet; import android.util.Log; import android.view.IWindowManager; import android.view.MotionEvent; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; +import com.android.systemui.statusbar.AutoHideUiElement; -/** A controller to control all auto-hide things. */ +import java.util.Set; + +import javax.inject.Inject; + +/** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */ public class AutoHideController { private static final String TAG = "AutoHideController"; + private static final long AUTO_HIDE_TIMEOUT_MS = 2250; private final IWindowManager mWindowManagerService; - private final Handler mHandler; - private final NotificationRemoteInputManager mRemoteInputManager; - private StatusBar mStatusBar; - private NavigationBarFragment mNavigationBar; + private final Set<AutoHideUiElement> mElements; private int mDisplayId; private boolean mAutoHideSuspended; - private static final long AUTO_HIDE_TIMEOUT_MS = 2250; - private final Runnable mAutoHide = () -> { if (isAnyTransientBarShown()) { hideTransientBars(); } }; - /** - * Injected constructor. See {@link StatusBarPhoneModule}. - */ + @Inject public AutoHideController(Context context, @Main Handler handler, - NotificationRemoteInputManager notificationRemoteInputManager, IWindowManager iWindowManager) { mHandler = handler; - mRemoteInputManager = notificationRemoteInputManager; mWindowManagerService = iWindowManager; + mElements = new ArraySet<>(); mDisplayId = context.getDisplayId(); } - void setStatusBar(StatusBar statusBar) { - mStatusBar = statusBar; + /** + * Adds an {@link AutoHideUiElement} whose behavior should be controlled by the + * {@link AutoHideController}. + */ + public void addAutoHideUiElement(AutoHideUiElement element) { + if (element != null) { + mElements.add(element); + } } - void setNavigationBar(NavigationBarFragment navigationBar) { - mNavigationBar = navigationBar; + /** + * Remove an {@link AutoHideUiElement} that was previously added. + */ + public void removeAutoHideUiElement(AutoHideUiElement element) { + if (element != null) { + mElements.remove(element); + } } private void hideTransientBars() { @@ -77,11 +85,9 @@ public class AutoHideController { } catch (RemoteException ex) { Log.w(TAG, "Cannot get WindowManager"); } - if (mStatusBar != null) { - mStatusBar.clearTransient(); - } - if (mNavigationBar != null) { - mNavigationBar.clearTransient(); + + for (AutoHideUiElement element : mElements) { + element.hide(); } } @@ -104,7 +110,8 @@ public class AutoHideController { mAutoHideSuspended = isAnyTransientBarShown(); } - void touchAutoHide() { + /** Schedules or cancels auto hide behavior based on current system bar state. */ + public void touchAutoHide() { // update transient bar auto hide if (isAnyTransientBarShown()) { scheduleAutoHide(); @@ -114,13 +121,15 @@ public class AutoHideController { } private Runnable getCheckBarModesRunnable() { - if (mStatusBar != null) { - return () -> mStatusBar.checkBarModes(); - } else if (mNavigationBar != null) { - return () -> mNavigationBar.checkNavBarModes(); - } else { + if (mElements.isEmpty()) { return null; } + + return () -> { + for (AutoHideUiElement element : mElements) { + element.synchronizeState(); + } + }; } private void cancelAutoHide() { @@ -134,14 +143,15 @@ public class AutoHideController { } void checkUserAutoHide(MotionEvent event) { - boolean shouldAutoHide = isAnyTransientBarShown() + boolean shouldHide = isAnyTransientBarShown() && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar. && event.getX() == 0 && event.getY() == 0; - if (mStatusBar != null) { - // a touch outside both bars - shouldAutoHide &= !mRemoteInputManager.getController().isRemoteInputActive(); + + for (AutoHideUiElement element : mElements) { + shouldHide &= element.shouldHideOnTouch(); } - if (shouldAutoHide) { + + if (shouldHide) { userAutoHide(); } } @@ -152,7 +162,11 @@ public class AutoHideController { } private boolean isAnyTransientBarShown() { - return (mStatusBar != null && mStatusBar.isTransientShown()) - || mNavigationBar != null && mNavigationBar.isTransientShown(); + for (AutoHideUiElement element : mElements) { + if (element.isVisible()) { + return true; + } + } + return false; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java index 5703f0653398..8e192c5bf17d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java @@ -172,7 +172,7 @@ public class LightsOutNotifController { @Override public void onEntryRemoved(@Nullable NotificationEntry entry, - NotificationVisibility visibility, boolean removedByUser) { + NotificationVisibility visibility, boolean removedByUser, int reason) { updateLightsOutView(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index fd8c71b48417..02cf8ccbef8b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -105,8 +105,10 @@ import com.android.systemui.recents.Recents; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; +import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener; @@ -166,6 +168,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private int mDisabledFlags2; private final Lazy<StatusBar> mStatusBarLazy; private final ShadeController mShadeController; + private final NotificationRemoteInputManager mNotificationRemoteInputManager; private Recents mRecents; private StatusBar mStatusBar; private final Divider mDivider; @@ -291,6 +294,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback CommandQueue commandQueue, Divider divider, Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy, ShadeController shadeController, + NotificationRemoteInputManager notificationRemoteInputManager, @Main Handler mainHandler) { mAccessibilityManagerWrapper = accessibilityManagerWrapper; mDeviceProvisionedController = deviceProvisionedController; @@ -300,6 +304,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mSysUiFlagsContainer = sysUiFlagsContainer; mStatusBarLazy = statusBarLazy; mShadeController = shadeController; + mNotificationRemoteInputManager = notificationRemoteInputManager; mAssistantAvailable = mAssistManager.getAssistInfoForUser(UserHandle.USER_CURRENT) != null; mOverviewProxyService = overviewProxyService; mNavigationModeController = navigationModeController; @@ -614,7 +619,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback clearTransient(); } - void clearTransient() { + private void clearTransient() { if (mTransientShown) { mTransientShown = false; handleTransientChanged(); @@ -1048,10 +1053,30 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback /** Sets {@link AutoHideController} to the navigation bar. */ public void setAutoHideController(AutoHideController autoHideController) { mAutoHideController = autoHideController; - mAutoHideController.setNavigationBar(this); + mAutoHideController.addAutoHideUiElement(new AutoHideUiElement() { + @Override + public void synchronizeState() { + checkNavBarModes(); + } + + @Override + public boolean shouldHideOnTouch() { + return !mNotificationRemoteInputManager.getController().isRemoteInputActive(); + } + + @Override + public boolean isVisible() { + return isTransientShown(); + } + + @Override + public void hide() { + clearTransient(); + } + }); } - boolean isTransientShown() { + private boolean isTransientShown() { return mTransientShown; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java index d709e029d0ee..8c31a372a756 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java @@ -196,7 +196,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis public void onEntryRemoved( @Nullable NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { // Removes any alerts pending on this entry. Note that this will not stop any inflation // tasks started by a transfer, so this should only be used as clean-up for when // inflation is stopped and the pending alert no longer needs to happen. 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 8729e04b2dec..f38d416a6f4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java @@ -44,8 +44,9 @@ import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.NotificationShadeWindowBlurController; +import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -91,6 +92,7 @@ public class NotificationShadeWindowViewController { private boolean mExpandAnimationRunning; private NotificationStackScrollLayout mStackScrollLayout; private PhoneStatusBarView mStatusBarView; + private PhoneStatusBarTransitions mBarTransitions; private StatusBar mService; private DragDownHelper mDragDownHelper; private boolean mDoubleTapEnabled; @@ -98,6 +100,7 @@ public class NotificationShadeWindowViewController { private boolean mExpandingBelowNotch; private final DockManager mDockManager; private final NotificationPanelViewController mNotificationPanelViewController; + private final SuperStatusBarViewFactory mStatusBarViewFactory; // Used for determining view / touch intersection private int[] mTempLocation = new int[2]; @@ -124,8 +127,9 @@ public class NotificationShadeWindowViewController { ShadeController shadeController, DockManager dockManager, @Nullable NotificationShadeWindowBlurController blurController, - NotificationShadeWindowView statusBarWindowView, - NotificationPanelViewController notificationPanelViewController) { + NotificationShadeWindowView notificationShadeWindowView, + NotificationPanelViewController notificationPanelViewController, + SuperStatusBarViewFactory statusBarViewFactory) { mInjectionInflationController = injectionInflationController; mCoordinator = coordinator; mPulseExpansionHandler = pulseExpansionHandler; @@ -141,11 +145,12 @@ public class NotificationShadeWindowViewController { mDozeLog = dozeLog; mDozeParameters = dozeParameters; mCommandQueue = commandQueue; - mView = statusBarWindowView; + mView = notificationShadeWindowView; mShadeController = shadeController; mDockManager = dockManager; mNotificationPanelViewController = notificationPanelViewController; mBlurController = blurController; + mStatusBarViewFactory = statusBarViewFactory; // This view is not part of the newly inflated expanded status bar. mBrightnessMirror = mView.findViewById(R.id.brightness_mirror); @@ -440,8 +445,18 @@ public class NotificationShadeWindowViewController { } } + public PhoneStatusBarTransitions getBarTransitions() { + return mBarTransitions; + } + public void setStatusBarView(PhoneStatusBarView statusBarView) { mStatusBarView = statusBarView; + if (statusBarView != null && mStatusBarViewFactory != null) { + mBarTransitions = new PhoneStatusBarTransitions( + statusBarView, + mStatusBarViewFactory.getStatusBarWindowView() + .findViewById(R.id.status_bar_container)); + } } public void setService(StatusBar statusBar) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 1ab36c5e3760..14af466a2424 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -16,15 +16,18 @@ package com.android.systemui.statusbar.phone; -import android.app.ActivityManager; +import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.AlarmManager; import android.app.AlarmManager.AlarmClockInfo; +import android.app.IActivityManager; import android.app.SynchronousUserSwitchObserver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.res.Resources; import android.media.AudioManager; import android.os.Handler; import android.os.RemoteException; @@ -33,13 +36,13 @@ import android.os.UserManager; import android.provider.Settings.Global; import android.service.notification.ZenModeConfig; import android.telecom.TelecomManager; -import android.telephony.TelephonyManager; import android.text.format.DateFormat; import android.util.Log; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.DisplayId; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; @@ -61,10 +64,13 @@ import com.android.systemui.statusbar.policy.RotationLockController.RotationLock import com.android.systemui.statusbar.policy.SensorPrivacyController; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.time.DateFormatUtil; import java.util.Locale; import java.util.concurrent.Executor; +import javax.inject.Inject; + /** * This class contains all of the policy about which icons are installed in the status bar at boot * time. It goes through the normal API for icons, even though it probably strictly doesn't need to. @@ -82,7 +88,7 @@ public class PhoneStatusBarPolicy private static final String TAG = "PhoneStatusBarPolicy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - public static final int LOCATION_STATUS_ICON_ID = + static final int LOCATION_STATUS_ICON_ID = com.android.internal.R.drawable.perm_group_location; private final String mSlotCast; @@ -97,20 +103,26 @@ public class PhoneStatusBarPolicy private final String mSlotHeadset; private final String mSlotDataSaver; private final String mSlotLocation; - private final String mSlotMicrophone; - private final String mSlotCamera; private final String mSlotSensorsOff; private final String mSlotScreenRecord; + private final int mDisplayId; + private final SharedPreferences mSharedPreferences; + private final DateFormatUtil mDateFormatUtil; + private final TelecomManager mTelecomManager; + private final AudioManager mAudioManager; - private final Context mContext; private final Handler mHandler = new Handler(); private final CastController mCast; private final HotspotController mHotspot; private final NextAlarmController mNextAlarmController; private final AlarmManager mAlarmManager; private final UserInfoController mUserInfoController; + private final IActivityManager mIActivityManager; private final UserManager mUserManager; private final StatusBarIconController mIconController; + private final CommandQueue mCommandQueue; + private final BroadcastDispatcher mBroadcastDispatcher; + private final Resources mResources; private final RotationLockController mRotationLockController; private final DataSaverController mDataSaver; private final ZenModeController mZenController; @@ -121,10 +133,6 @@ public class PhoneStatusBarPolicy private final SensorPrivacyController mSensorPrivacyController; private final RecordingController mRecordingController; - // Assume it's all good unless we hear otherwise. We don't always seem - // to get broadcasts that it *is* there. - int mSimState = TelephonyManager.SIM_STATE_READY; - private boolean mZenVisible; private boolean mVolumeVisible; private boolean mCurrentUserSetup; @@ -134,47 +142,70 @@ public class PhoneStatusBarPolicy private BluetoothController mBluetooth; private AlarmManager.AlarmClockInfo mNextAlarm; - public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController, + @Inject + public PhoneStatusBarPolicy(StatusBarIconController iconController, CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher, - @UiBackground Executor uiBgExecutor) { - mContext = context; + @UiBackground Executor uiBgExecutor, @Main Resources resources, + CastController castController, HotspotController hotspotController, + BluetoothController bluetoothController, NextAlarmController nextAlarmController, + UserInfoController userInfoController, RotationLockController rotationLockController, + DataSaverController dataSaverController, ZenModeController zenModeController, + DeviceProvisionedController deviceProvisionedController, + KeyguardStateController keyguardStateController, + LocationController locationController, + SensorPrivacyController sensorPrivacyController, IActivityManager iActivityManager, + AlarmManager alarmManager, UserManager userManager, AudioManager audioManager, + RecordingController recordingController, + @Nullable TelecomManager telecomManager, @DisplayId int displayId, + @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil) { mIconController = iconController; - mCast = Dependency.get(CastController.class); - mHotspot = Dependency.get(HotspotController.class); - mBluetooth = Dependency.get(BluetoothController.class); - mNextAlarmController = Dependency.get(NextAlarmController.class); - mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - mUserInfoController = Dependency.get(UserInfoController.class); - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mRotationLockController = Dependency.get(RotationLockController.class); - mDataSaver = Dependency.get(DataSaverController.class); - mZenController = Dependency.get(ZenModeController.class); - mProvisionedController = Dependency.get(DeviceProvisionedController.class); - mKeyguardStateController = Dependency.get(KeyguardStateController.class); - mLocationController = Dependency.get(LocationController.class); - mSensorPrivacyController = Dependency.get(SensorPrivacyController.class); - mRecordingController = Dependency.get(RecordingController.class); + mCommandQueue = commandQueue; + mBroadcastDispatcher = broadcastDispatcher; + mResources = resources; + mCast = castController; + mHotspot = hotspotController; + mBluetooth = bluetoothController; + mNextAlarmController = nextAlarmController; + mAlarmManager = alarmManager; + mUserInfoController = userInfoController; + mIActivityManager = iActivityManager; + mUserManager = userManager; + mRotationLockController = rotationLockController; + mDataSaver = dataSaverController; + mZenController = zenModeController; + mProvisionedController = deviceProvisionedController; + mKeyguardStateController = keyguardStateController; + mLocationController = locationController; + mSensorPrivacyController = sensorPrivacyController; + mRecordingController = recordingController; mUiBgExecutor = uiBgExecutor; - - mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast); - mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot); - mSlotBluetooth = context.getString(com.android.internal.R.string.status_bar_bluetooth); - mSlotTty = context.getString(com.android.internal.R.string.status_bar_tty); - mSlotZen = context.getString(com.android.internal.R.string.status_bar_zen); - mSlotVolume = context.getString(com.android.internal.R.string.status_bar_volume); - mSlotAlarmClock = context.getString(com.android.internal.R.string.status_bar_alarm_clock); - mSlotManagedProfile = context.getString( + mAudioManager = audioManager; + mTelecomManager = telecomManager; + + mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast); + mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot); + mSlotBluetooth = resources.getString(com.android.internal.R.string.status_bar_bluetooth); + mSlotTty = resources.getString(com.android.internal.R.string.status_bar_tty); + mSlotZen = resources.getString(com.android.internal.R.string.status_bar_zen); + mSlotVolume = resources.getString(com.android.internal.R.string.status_bar_volume); + mSlotAlarmClock = resources.getString(com.android.internal.R.string.status_bar_alarm_clock); + mSlotManagedProfile = resources.getString( com.android.internal.R.string.status_bar_managed_profile); - mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate); - mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset); - mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver); - mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location); - mSlotMicrophone = context.getString(com.android.internal.R.string.status_bar_microphone); - mSlotCamera = context.getString(com.android.internal.R.string.status_bar_camera); - mSlotSensorsOff = context.getString(com.android.internal.R.string.status_bar_sensors_off); - mSlotScreenRecord = context.getString( + mSlotRotate = resources.getString(com.android.internal.R.string.status_bar_rotate); + mSlotHeadset = resources.getString(com.android.internal.R.string.status_bar_headset); + mSlotDataSaver = resources.getString(com.android.internal.R.string.status_bar_data_saver); + mSlotLocation = resources.getString(com.android.internal.R.string.status_bar_location); + mSlotSensorsOff = resources.getString(com.android.internal.R.string.status_bar_sensors_off); + mSlotScreenRecord = resources.getString( com.android.internal.R.string.status_bar_screen_record); + mDisplayId = displayId; + mSharedPreferences = sharedPreferences; + mDateFormatUtil = dateFormatUtil; + } + + /** Initialize the object after construction. */ + public void init() { // listen for broadcasts IntentFilter filter = new IntentFilter(); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); @@ -185,11 +216,11 @@ public class PhoneStatusBarPolicy filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); - broadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler); + mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler); // listen for user / profile change. try { - ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG); + mIActivityManager.registerUserSwitchObserver(mUserSwitchListener, TAG); } catch (RemoteException e) { // Ignore } @@ -219,26 +250,26 @@ public class PhoneStatusBarPolicy // hotspot mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot, - mContext.getString(R.string.accessibility_status_bar_hotspot)); + mResources.getString(R.string.accessibility_status_bar_hotspot)); mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled()); // managed profile mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status, - mContext.getString(R.string.accessibility_managed_profile)); + mResources.getString(R.string.accessibility_managed_profile)); mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible); // data saver mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver, - context.getString(R.string.accessibility_data_saver_on)); + mResources.getString(R.string.accessibility_data_saver_on)); mIconController.setIconVisibility(mSlotDataSaver, false); mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID, - mContext.getString(R.string.accessibility_location_active)); + mResources.getString(R.string.accessibility_location_active)); mIconController.setIconVisibility(mSlotLocation, false); // sensors off mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off, - mContext.getString(R.string.accessibility_sensors_off_active)); + mResources.getString(R.string.accessibility_sensors_off_active)); mIconController.setIconVisibility(mSlotSensorsOff, mSensorPrivacyController.isSensorPrivacyEnabled()); @@ -259,7 +290,7 @@ public class PhoneStatusBarPolicy mLocationController.addCallback(this); mRecordingController.addCallback(this); - commandQueue.addCallback(this); + mCommandQueue.addCallback(this); } @Override @@ -284,51 +315,17 @@ public class PhoneStatusBarPolicy private String buildAlarmContentDescription() { if (mNextAlarm == null) { - return mContext.getString(R.string.status_bar_alarm); + return mResources.getString(R.string.status_bar_alarm); } - return formatNextAlarm(mNextAlarm, mContext); - } - private static String formatNextAlarm(AlarmManager.AlarmClockInfo info, Context context) { - if (info == null) { - return ""; - } - String skeleton = DateFormat.is24HourFormat( - context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma"; + String skeleton = mDateFormatUtil.is24HourFormat() ? "EHm" : "Ehma"; String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); - String dateString = DateFormat.format(pattern, info.getTriggerTime()).toString(); + String dateString = DateFormat.format(pattern, mNextAlarm.getTriggerTime()).toString(); - return context.getString(R.string.accessibility_quick_settings_alarm, dateString); - } - - private final void updateSimState(Intent intent) { - String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE); - if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) { - mSimState = TelephonyManager.SIM_STATE_READY; - } else if (Intent.SIM_STATE_CARD_IO_ERROR.equals(stateExtra)) { - mSimState = TelephonyManager.SIM_STATE_CARD_IO_ERROR; - } else if (Intent.SIM_STATE_CARD_RESTRICTED.equals(stateExtra)) { - mSimState = TelephonyManager.SIM_STATE_CARD_RESTRICTED; - } else if (Intent.SIM_STATE_READY.equals(stateExtra)) { - mSimState = TelephonyManager.SIM_STATE_READY; - } else if (Intent.SIM_STATE_LOCKED.equals(stateExtra)) { - final String lockedReason = - intent.getStringExtra(Intent.EXTRA_SIM_LOCKED_REASON); - if (Intent.SIM_LOCKED_ON_PIN.equals(lockedReason)) { - mSimState = TelephonyManager.SIM_STATE_PIN_REQUIRED; - } else if (Intent.SIM_LOCKED_ON_PUK.equals(lockedReason)) { - mSimState = TelephonyManager.SIM_STATE_PUK_REQUIRED; - } else { - mSimState = TelephonyManager.SIM_STATE_NETWORK_LOCKED; - } - } else { - mSimState = TelephonyManager.SIM_STATE_UNKNOWN; - } + return mResources.getString(R.string.accessibility_quick_settings_alarm, dateString); } private final void updateVolumeZen() { - AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - boolean zenVisible = false; int zenIconId = 0; String zenDescription = null; @@ -338,29 +335,29 @@ public class PhoneStatusBarPolicy String volumeDescription = null; int zen = mZenController.getZen(); - if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) { + if (DndTile.isVisible(mSharedPreferences) || DndTile.isCombinedIcon(mSharedPreferences)) { zenVisible = zen != Global.ZEN_MODE_OFF; zenIconId = R.drawable.stat_sys_dnd; - zenDescription = mContext.getString(R.string.quick_settings_dnd_label); + zenDescription = mResources.getString(R.string.quick_settings_dnd_label); } else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) { zenVisible = true; zenIconId = R.drawable.stat_sys_dnd; - zenDescription = mContext.getString(R.string.interruption_level_none); + zenDescription = mResources.getString(R.string.interruption_level_none); } else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) { zenVisible = true; zenIconId = R.drawable.stat_sys_dnd; - zenDescription = mContext.getString(R.string.interruption_level_priority); + zenDescription = mResources.getString(R.string.interruption_level_priority); } if (!ZenModeConfig.isZenOverridingRinger(zen, mZenController.getConsolidatedPolicy())) { - if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) { + if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) { volumeVisible = true; volumeIconId = R.drawable.stat_sys_ringer_vibrate; - volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate); - } else if (audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) { + volumeDescription = mResources.getString(R.string.accessibility_ringer_vibrate); + } else if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) { volumeVisible = true; volumeIconId = R.drawable.stat_sys_ringer_silent; - volumeDescription = mContext.getString(R.string.accessibility_ringer_silent); + volumeDescription = mResources.getString(R.string.accessibility_ringer_silent); } } @@ -395,13 +392,13 @@ public class PhoneStatusBarPolicy private final void updateBluetooth() { int iconId = R.drawable.stat_sys_data_bluetooth_connected; String contentDescription = - mContext.getString(R.string.accessibility_quick_settings_bluetooth_on); + mResources.getString(R.string.accessibility_quick_settings_bluetooth_on); boolean bluetoothVisible = false; if (mBluetooth != null) { if (mBluetooth.isBluetoothConnected() && (mBluetooth.isBluetoothAudioActive() || !mBluetooth.isBluetoothAudioProfileOnly())) { - contentDescription = mContext.getString( + contentDescription = mResources.getString( R.string.accessibility_bluetooth_connected); bluetoothVisible = mBluetooth.isBluetoothEnabled(); } @@ -412,12 +409,10 @@ public class PhoneStatusBarPolicy } private final void updateTTY() { - TelecomManager telecomManager = - (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); - if (telecomManager == null) { + if (mTelecomManager == null) { updateTTY(TelecomManager.TTY_MODE_OFF); } else { - updateTTY(telecomManager.getCurrentTtyMode()); + updateTTY(mTelecomManager.getCurrentTtyMode()); } } @@ -430,7 +425,7 @@ public class PhoneStatusBarPolicy // TTY is on if (DEBUG) Log.v(TAG, "updateTTY: set TTY on"); mIconController.setIcon(mSlotTty, R.drawable.stat_sys_tty_mode, - mContext.getString(R.string.accessibility_tty_enabled)); + mResources.getString(R.string.accessibility_tty_enabled)); mIconController.setIconVisibility(mSlotTty, true); } else { // TTY is off @@ -452,7 +447,7 @@ public class PhoneStatusBarPolicy mHandler.removeCallbacks(mRemoveCastIconRunnable); if (isCasting && !mRecordingController.isRecording()) { // screen record has its own icon mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, - mContext.getString(R.string.accessibility_casting)); + mResources.getString(R.string.accessibility_casting)); mIconController.setIconVisibility(mSlotCast, true); } else { // don't turn off the screen-record icon for a few seconds, just to make sure the user @@ -478,7 +473,7 @@ public class PhoneStatusBarPolicy showIcon = true; mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status, - mContext.getString(R.string.accessibility_managed_profile)); + mResources.getString(R.string.accessibility_managed_profile)); } else { showIcon = false; } @@ -545,7 +540,7 @@ public class PhoneStatusBarPolicy @Override public void appTransitionStarting(int displayId, long startTime, long duration, boolean forced) { - if (mContext.getDisplayId() == displayId) { + if (mDisplayId == displayId) { updateManagedProfile(); } } @@ -567,14 +562,14 @@ public class PhoneStatusBarPolicy @Override public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) { boolean portrait = RotationLockTile.isCurrentOrientationLockPortrait( - mRotationLockController, mContext); + mRotationLockController, mResources); if (rotationLocked) { if (portrait) { mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_portrait, - mContext.getString(R.string.accessibility_rotation_lock_on_portrait)); + mResources.getString(R.string.accessibility_rotation_lock_on_portrait)); } else { mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape, - mContext.getString(R.string.accessibility_rotation_lock_on_landscape)); + mResources.getString(R.string.accessibility_rotation_lock_on_landscape)); } mIconController.setIconVisibility(mSlotRotate, true); } else { @@ -586,7 +581,7 @@ public class PhoneStatusBarPolicy boolean connected = intent.getIntExtra("state", 0) != 0; boolean hasMic = intent.getIntExtra("microphone", 0) != 0; if (connected) { - String contentDescription = mContext.getString(hasMic + String contentDescription = mResources.getString(hasMic ? R.string.accessibility_status_bar_headset : R.string.accessibility_status_bar_headphones); mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic @@ -630,7 +625,6 @@ public class PhoneStatusBarPolicy if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { break; } - updateSimState(intent); break; case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED: updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java index e8bc2f58adb4..2052ee6cdac5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java @@ -29,23 +29,21 @@ public final class PhoneStatusBarTransitions extends BarTransitions { private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK = 0.5f; private static final float ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK = 0; - private final PhoneStatusBarView mView; private final float mIconAlphaWhenOpaque; - private View mLeftSide, mStatusIcons, mBattery, mClock; + private View mLeftSide, mStatusIcons, mBattery; private Animator mCurrentAnimation; - public PhoneStatusBarTransitions(PhoneStatusBarView view) { - super(view, R.drawable.status_background); - mView = view; - final Resources res = mView.getContext().getResources(); + /** + * @param backgroundView view to apply the background drawable + */ + public PhoneStatusBarTransitions(PhoneStatusBarView statusBarView, View backgroundView) { + super(backgroundView, R.drawable.status_background); + final Resources res = statusBarView.getContext().getResources(); mIconAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1); - } - - public void init() { - mLeftSide = mView.findViewById(R.id.status_bar_left_side); - mStatusIcons = mView.findViewById(R.id.statusIcons); - mBattery = mView.findViewById(R.id.battery); + mLeftSide = statusBarView.findViewById(R.id.status_bar_left_side); + mStatusIcons = statusBarView.findViewById(R.id.statusIcons); + mBattery = statusBarView.findViewById(R.id.battery); applyModeBackground(-1, getMode(), false /*animate*/); applyMode(getMode(), false /*animate*/); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index b949e3a5080c..1359f74d0b3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -53,7 +53,6 @@ public class PhoneStatusBarView extends PanelBar { StatusBar mBar; boolean mIsFullyOpenedPanel = false; - private final PhoneStatusBarTransitions mBarTransitions; private ScrimController mScrimController; private float mMinFraction; private Runnable mHideExpandedRunnable = new Runnable() { @@ -83,15 +82,9 @@ public class PhoneStatusBarView extends PanelBar { public PhoneStatusBarView(Context context, AttributeSet attrs) { super(context, attrs); - - mBarTransitions = new PhoneStatusBarTransitions(this); mCommandQueue = Dependency.get(CommandQueue.class); } - public BarTransitions getBarTransitions() { - return mBarTransitions; - } - public void setBar(StatusBar bar) { mBar = bar; } @@ -102,7 +95,6 @@ public class PhoneStatusBarView extends PanelBar { @Override public void onFinishInflate() { - mBarTransitions.init(); mBattery = findViewById(R.id.battery); mCutoutSpace = findViewById(R.id.cutout_space_view); mCenterIconSpace = findViewById(R.id.centered_icon_area); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 0d3b09a634e4..19df9727c97c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -163,6 +163,7 @@ import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; @@ -676,6 +677,7 @@ public class StatusBar extends SystemUI implements DemoMode, KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, + PhoneStatusBarPolicy phoneStatusBarPolicy, DismissCallbackRegistry dismissCallbackRegistry, StatusBarTouchableRegionManager statusBarTouchableRegionManager) { super(context); @@ -751,6 +753,7 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardDismissUtil = keyguardDismissUtil; mExtensionController = extensionController; mUserInfoControllerImpl = userInfoControllerImpl; + mIconPolicy = phoneStatusBarPolicy; mDismissCallbackRegistry = dismissCallbackRegistry; mBubbleExpandListener = @@ -875,8 +878,7 @@ public class StatusBar extends SystemUI implements DemoMode, // end old BaseStatusBar.start(). // Lastly, call to the icon policy to install/update all the icons. - mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCommandQueue, - mBroadcastDispatcher, mUiBgExecutor); + mIconPolicy.init(); mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController); mKeyguardStateController.addCallback(this); @@ -1073,7 +1075,27 @@ public class StatusBar extends SystemUI implements DemoMode, } }); - mAutoHideController.setStatusBar(this); + mAutoHideController.addAutoHideUiElement(new AutoHideUiElement() { + @Override + public void synchronizeState() { + checkBarModes(); + } + + @Override + public boolean shouldHideOnTouch() { + return !mRemoteInputManager.getController().isRemoteInputActive(); + } + + @Override + public boolean isVisible() { + return isTransientShown(); + } + + @Override + public void hide() { + clearTransient(); + } + }); ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind); ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front); @@ -2227,7 +2249,7 @@ public class StatusBar extends SystemUI implements DemoMode, clearTransient(); } - void clearTransient() { + private void clearTransient() { if (mTransientShown) { mTransientShown = false; handleTransientChanged(); @@ -2305,13 +2327,14 @@ public class StatusBar extends SystemUI implements DemoMode, } protected BarTransitions getStatusBarTransitions() { - return mStatusBarView.getBarTransitions(); + return mNotificationShadeWindowViewController.getBarTransitions(); } void checkBarModes() { if (mDemoMode) return; - if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState, - getStatusBarTransitions()); + if (mNotificationShadeWindowViewController != null) { + checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions()); + } mNavigationBarController.checkNavBarModes(mDisplayId); mNoAnimationOnNextBarModeChange = false; } @@ -2329,8 +2352,9 @@ public class StatusBar extends SystemUI implements DemoMode, } private void finishBarAnimations() { - if (mStatusBarView != null) { - mStatusBarView.getBarTransitions().finishAnimations(); + if (mNotificationShadeWindowController != null + && mNotificationShadeWindowViewController.getBarTransitions() != null) { + mNotificationShadeWindowViewController.getBarTransitions().finishAnimations(); } mNavigationBarController.finishBarAnimations(mDisplayId); } @@ -2396,12 +2420,11 @@ public class StatusBar extends SystemUI implements DemoMode, pw.print(" mDozing="); pw.println(mDozing); pw.print(" mWallpaperSupported= "); pw.println(mWallpaperSupported); - if (mStatusBarView != null) { - dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions()); - } pw.println(" StatusBarWindowView: "); if (mNotificationShadeWindowViewController != null) { mNotificationShadeWindowViewController.dump(fd, pw, args); + dumpBarTransitions(pw, "PhoneStatusBarTransitions", + mNotificationShadeWindowViewController.getBarTransitions()); } pw.println(" mMediaManager: "); @@ -3004,8 +3027,10 @@ public class StatusBar extends SystemUI implements DemoMode, -1; if (barMode != -1) { boolean animate = true; - if (mStatusBarView != null) { - mStatusBarView.getBarTransitions().transitionTo(barMode, animate); + if (mNotificationShadeWindowController != null + && mNotificationShadeWindowViewController.getBarTransitions() != null) { + mNotificationShadeWindowViewController.getBarTransitions().transitionTo( + barMode, animate); } mNavigationBarController.transitionTo(mDisplayId, barMode, animate); } @@ -4258,7 +4283,7 @@ public class StatusBar extends SystemUI implements DemoMode, return mGutsManager; } - boolean isTransientShown() { + private boolean isTransientShown() { return mTransientShown; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 693cdd21884c..30d6b5079166 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -199,7 +199,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, public void onEntryRemoved( @Nullable NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, + int reason) { StatusBarNotificationPresenter.this.onNotificationRemoved( entry.getKey(), entry.getSbn()); if (removedByUser) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneDependenciesModule.java index fcf698cae49b..69c6814090d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneDependenciesModule.java @@ -16,14 +16,7 @@ package com.android.systemui.statusbar.phone.dagger; -import android.content.Context; -import android.os.Handler; -import android.view.IWindowManager; - -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.row.RowContentBindStage; -import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.StatusBar; @@ -39,16 +32,6 @@ import dagger.Provides; */ @Module public interface StatusBarPhoneDependenciesModule { - /** */ - @Singleton - @Provides - static AutoHideController newAutoHideController(Context context, - @Main Handler handler, - NotificationRemoteInputManager notificationRemoteInputManager, - IWindowManager iWindowManager) { - return new AutoHideController(context, handler, notificationRemoteInputManager, - iWindowManager); - } /** */ @Singleton diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index e64f8214bb71..0a4fdc9eb9bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -79,6 +79,7 @@ import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; +import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; @@ -193,6 +194,7 @@ public interface StatusBarPhoneModule { KeyguardDismissUtil keyguardDismissUtil, ExtensionController extensionController, UserInfoControllerImpl userInfoControllerImpl, + PhoneStatusBarPolicy phoneStatusBarPolicy, DismissCallbackRegistry dismissCallbackRegistry, StatusBarTouchableRegionManager statusBarTouchableRegionManager) { return new StatusBar( @@ -269,6 +271,7 @@ public interface StatusBarPhoneModule { keyguardDismissUtil, extensionController, userInfoControllerImpl, + phoneStatusBarPolicy, dismissCallbackRegistry, statusBarTouchableRegionManager); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index d0904049d85a..7d532a88caac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -56,8 +56,9 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof private int mHotspotState; private volatile int mNumConnectedDevices; - private volatile boolean mIsTetheringSupported; - private volatile boolean mHasTetherableWifiRegexs; + // Assume tethering is available until told otherwise + private volatile boolean mIsTetheringSupported = true; + private volatile boolean mHasTetherableWifiRegexs = true; private boolean mWaitingForTerminalState; private TetheringManager.TetheringEventCallback mTetheringCallback = @@ -97,6 +98,15 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof new HandlerExecutor(backgroundHandler), mTetheringCallback); } + /** + * Whether hotspot is currently supported. + * + * This will return {@code true} immediately on creation of the controller, but may be updated + * later. Callbacks from this controllers will notify if the state changes. + * + * @return {@code true} if hotspot is supported (or we haven't been told it's not) + * @see #addCallback + */ @Override public boolean isHotspotSupported() { return mIsTetheringSupported && mHasTetherableWifiRegexs diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 9003de18ec93..d2d76c7e853c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE; @@ -157,6 +158,7 @@ public class NetworkControllerImpl extends BroadcastReceiver ServiceState mLastServiceState; private boolean mUserSetup; private boolean mSimDetected; + private boolean mForceCellularValidated; private ConfigurationController.ConfigurationListener mConfigurationListener = new ConfigurationController.ConfigurationListener() { @@ -284,12 +286,41 @@ public class NetworkControllerImpl extends BroadcastReceiver mPhoneStateListener = new PhoneStateListener(mReceiverHandler::post) { @Override public void onActiveDataSubscriptionIdChanged(int subId) { + // For data switching from A to B, we assume B is validated for up to 2 seconds iff: + // 1) A and B are in the same subscription group e.g. CBRS data switch. And + // 2) A was validated before the switch. + // This is to provide smooth transition for UI without showing cross during data + // switch. + if (keepCellularValidationBitInSwitch(mActiveMobileDataSubscription, subId)) { + if (DEBUG) Log.d(TAG, ": mForceCellularValidated to true."); + mForceCellularValidated = true; + mReceiverHandler.removeCallbacks(mClearForceValidated); + mReceiverHandler.postDelayed(mClearForceValidated, 2000); + } mActiveMobileDataSubscription = subId; doUpdateMobileControllers(); } }; } + private final Runnable mClearForceValidated = () -> { + if (DEBUG) Log.d(TAG, ": mClearForceValidated"); + mForceCellularValidated = false; + updateConnectivity(); + }; + + boolean isInGroupDataSwitch(int subId1, int subId2) { + SubscriptionInfo info1 = mSubscriptionManager.getActiveSubscriptionInfo(subId1); + SubscriptionInfo info2 = mSubscriptionManager.getActiveSubscriptionInfo(subId2); + return (info1 != null && info2 != null && info1.getGroupUuid() != null + && info1.getGroupUuid().equals(info2.getGroupUuid())); + } + + boolean keepCellularValidationBitInSwitch(int sourceSubId, int destSubId) { + return mValidatedTransports.get(TRANSPORT_CELLULAR) + && isInGroupDataSwitch(sourceSubId, destSubId); + } + public DataSaverController getDataSaverController() { return mDataSaverController; } @@ -793,6 +824,8 @@ public class NetworkControllerImpl extends BroadcastReceiver } } + if (mForceCellularValidated) mValidatedTransports.set(TRANSPORT_CELLULAR); + if (CHATTY) { Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports); Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputUriController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputUriController.java index 4d912deb7d41..b5031832adc5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputUriController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputUriController.java @@ -73,7 +73,7 @@ public class RemoteInputUriController { private final NotificationEntryListener mInlineUriListener = new NotificationEntryListener() { @Override public void onEntryRemoved(NotificationEntry entry, NotificationVisibility visibility, - boolean removedByUser) { + boolean removedByUser, int reason) { try { mStatusBarManagerService.clearInlineReplyUriPermissions(entry.getKey()); } catch (RemoteException ex) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 312c4ac75bfa..d29f4fcd0c26 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -31,14 +31,12 @@ import android.net.IConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; -import android.os.AsyncTask; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.security.KeyChain; -import android.security.KeyChain.KeyChainConnection; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -55,6 +53,7 @@ import com.android.systemui.settings.CurrentUserTracker; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.concurrent.Executor; import javax.inject.Inject; import javax.inject.Singleton; @@ -85,7 +84,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi private final DevicePolicyManager mDevicePolicyManager; private final PackageManager mPackageManager; private final UserManager mUserManager; - private final Handler mBgHandler; + private final Executor mBgExecutor; @GuardedBy("mCallbacks") private final ArrayList<SecurityControllerCallback> mCallbacks = new ArrayList<>(); @@ -101,16 +100,14 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi /** */ @Inject - public SecurityControllerImpl(Context context, @Background Handler bgHandler, - BroadcastDispatcher broadcastDispatcher) { - this(context, bgHandler, broadcastDispatcher, null); - } - - public SecurityControllerImpl(Context context, Handler bgHandler, - BroadcastDispatcher broadcastDispatcher, SecurityControllerCallback callback) { + public SecurityControllerImpl( + Context context, + @Background Handler bgHandler, + BroadcastDispatcher broadcastDispatcher, + @Background Executor bgExecutor + ) { super(broadcastDispatcher); mContext = context; - mBgHandler = bgHandler; mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); mConnectivityManager = (ConnectivityManager) @@ -118,10 +115,8 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi mConnectivityManagerService = IConnectivityManager.Stub.asInterface( ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); mPackageManager = context.getPackageManager(); - mUserManager = (UserManager) - context.getSystemService(Context.USER_SERVICE); - - addCallback(callback); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mBgExecutor = bgExecutor; IntentFilter filter = new IntentFilter(); filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED); @@ -305,7 +300,23 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi } private void refreshCACerts(int userId) { - new CACertLoader().execute(userId); + mBgExecutor.execute(() -> { + Pair<Integer, Boolean> idWithCert = null; + try (KeyChain.KeyChainConnection conn = KeyChain.bindAsUser(mContext, + UserHandle.of(userId))) { + boolean hasCACerts = !(conn.getService().getUserCaAliases().getList().isEmpty()); + idWithCert = new Pair<Integer, Boolean>(userId, hasCACerts); + } catch (RemoteException | InterruptedException | AssertionError e) { + Log.i(TAG, "failed to get CA certs", e); + idWithCert = new Pair<Integer, Boolean>(userId, null); + } finally { + if (DEBUG) Log.d(TAG, "Refreshing CA Certs " + idWithCert); + if (idWithCert != null && idWithCert.second != null) { + mHasCACerts.put(idWithCert.first, idWithCert.second); + fireCallbacks(); + } + } + }); } private String getNameForVpnConfig(VpnConfig cfg, UserHandle user) { @@ -408,28 +419,4 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi } } }; - - protected class CACertLoader extends AsyncTask<Integer, Void, Pair<Integer, Boolean> > { - - @Override - protected Pair<Integer, Boolean> doInBackground(Integer... userId) { - try (KeyChainConnection conn = KeyChain.bindAsUser(mContext, - UserHandle.of(userId[0]))) { - boolean hasCACerts = !(conn.getService().getUserCaAliases().getList().isEmpty()); - return new Pair<Integer, Boolean>(userId[0], hasCACerts); - } catch (RemoteException | InterruptedException | AssertionError e) { - Log.i(TAG, "failed to get CA certs", e); - return new Pair<Integer, Boolean>(userId[0], null); - } - } - - @Override - protected void onPostExecute(Pair<Integer, Boolean> result) { - if (DEBUG) Log.d(TAG, "onPostExecute " + result); - if (result.second != null) { - mHasCACerts.put(result.first, result.second); - fireCallbacks(); - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java index 86fe300820a3..311e873812ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java @@ -25,10 +25,10 @@ import android.text.TextUtils; import android.util.KeyValueListParser; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.util.DeviceConfigProxy; import javax.inject.Inject; import javax.inject.Singleton; @@ -62,10 +62,15 @@ public final class SmartReplyConstants { private final Handler mHandler; private final Context mContext; + private final DeviceConfigProxy mDeviceConfig; private final KeyValueListParser mParser = new KeyValueListParser(','); @Inject - public SmartReplyConstants(@Main Handler handler, Context context) { + public SmartReplyConstants( + @Main Handler handler, + Context context, + DeviceConfigProxy deviceConfig + ) { mHandler = handler; mContext = context; final Resources resources = mContext.getResources(); @@ -86,31 +91,35 @@ public final class SmartReplyConstants { mDefaultOnClickInitDelay = resources.getInteger( R.integer.config_smart_replies_in_notifications_onclick_init_delay); + mDeviceConfig = deviceConfig; registerDeviceConfigListener(); updateConstants(); } private void registerDeviceConfigListener() { - DeviceConfig.addOnPropertiesChangedListener( + mDeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, this::postToHandler, - (properties) -> onDeviceConfigPropertiesChanged(properties.getNamespace())); + mOnPropertiesChangedListener); } private void postToHandler(Runnable r) { this.mHandler.post(r); } - @VisibleForTesting - void onDeviceConfigPropertiesChanged(String namespace) { - if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) { - Log.e(TAG, "Received update from DeviceConfig for unrelated namespace: " - + namespace); - return; - } - - updateConstants(); - } + private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) { + Log.e(TAG, + "Received update from DeviceConfig for unrelated namespace: " + + properties.getNamespace()); + return; + } + updateConstants(); + } + }; private void updateConstants() { synchronized (SmartReplyConstants.this) { @@ -120,7 +129,7 @@ public final class SmartReplyConstants { mRequiresTargetingP = readDeviceConfigBooleanOrDefaultIfEmpty( SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P, mDefaultRequiresP); - mMaxSqueezeRemeasureAttempts = DeviceConfig.getInt( + mMaxSqueezeRemeasureAttempts = mDeviceConfig.getInt( DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS, mDefaultMaxSqueezeRemeasureAttempts); @@ -130,24 +139,24 @@ public final class SmartReplyConstants { mShowInHeadsUp = readDeviceConfigBooleanOrDefaultIfEmpty( SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP, mDefaultShowInHeadsUp); - mMinNumSystemGeneratedReplies = DeviceConfig.getInt( + mMinNumSystemGeneratedReplies = mDeviceConfig.getInt( DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.SSIN_MIN_NUM_SYSTEM_GENERATED_REPLIES, mDefaultMinNumSystemGeneratedReplies); - mMaxNumActions = DeviceConfig.getInt( + mMaxNumActions = mDeviceConfig.getInt( DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.SSIN_MAX_NUM_ACTIONS, mDefaultMaxNumActions); - mOnClickInitDelay = DeviceConfig.getInt( + mOnClickInitDelay = mDeviceConfig.getInt( DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.SSIN_ONCLICK_INIT_DELAY, mDefaultOnClickInitDelay); } } - private static boolean readDeviceConfigBooleanOrDefaultIfEmpty(String propertyName, + private boolean readDeviceConfigBooleanOrDefaultIfEmpty(String propertyName, boolean defaultValue) { - String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, propertyName); + String value = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, propertyName); if (TextUtils.isEmpty(value)) { return defaultValue; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 8bd0f2cadb2b..7c963869ed47 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -88,15 +88,16 @@ public class WifiSignalController extends boolean wifiVisible = mCurrentState.enabled && ((mCurrentState.connected && mCurrentState.inetCondition == 1) || !mHasMobileData || visibleWhenEnabled); - String wifiDesc = wifiVisible ? mCurrentState.ssid : null; + String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null; boolean ssidPresent = wifiVisible && mCurrentState.ssid != null; String contentDescription = getTextIfExists(getContentDescription()).toString(); if (mCurrentState.inetCondition == 0) { contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet)); } IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription); - IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(), - contentDescription); + IconState qsIcon = new IconState(mCurrentState.connected, + mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected + : getQsCurrentIconId(), contentDescription); callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon, ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut, wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 241d9783c6e0..07985ab5a43c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -74,11 +74,6 @@ public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks { startSystemActivity(new Intent(ACTION_OPEN_TV_NOTIFICATIONS_PANEL)); } - @Override - public void animateCollapsePanels(int flags, boolean force) { - startSystemActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)); - } - private void startSystemActivity(Intent intent) { PackageManager pm = mContext.getPackageManager(); ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_SYSTEM_ONLY); diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java index edab4a72d8c8..0242e8349364 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java @@ -21,21 +21,16 @@ import android.annotation.Nullable; import android.app.INotificationManager; import android.app.ITransientNotificationCallback; import android.content.Context; -import android.content.res.Configuration; -import android.graphics.PixelFormat; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; -import android.widget.TextView; import android.widget.Toast; +import android.widget.ToastPresenter; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -64,6 +59,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { private final WindowManager mWindowManager; private final INotificationManager mNotificationManager; private final AccessibilityManager mAccessibilityManager; + private final ToastPresenter mPresenter; private ToastEntry mCurrentToast; @Inject @@ -83,6 +79,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { mWindowManager = windowManager; mNotificationManager = notificationManager; mAccessibilityManager = accessibilityManager; + mPresenter = new ToastPresenter(context, accessibilityManager); } @Override @@ -97,8 +94,8 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { if (mCurrentToast != null) { hideCurrentToast(); } - View view = getView(text); - LayoutParams params = getLayoutParams(windowToken, duration); + View view = mPresenter.getTextToastView(text); + LayoutParams params = getLayoutParams(packageName, windowToken, duration); mCurrentToast = new ToastEntry(packageName, token, view, windowToken, callback); try { mWindowManager.addView(view, params); @@ -106,7 +103,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { Log.w(TAG, "Error while attempting to show toast from " + packageName, e); return; } - trySendAccessibilityEvent(view, packageName); + mPresenter.trySendAccessibilityEvent(view, packageName); if (callback != null) { try { callback.onToastShown(); @@ -148,56 +145,13 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { mCurrentToast = null; } - private void trySendAccessibilityEvent(View view, String packageName) { - if (!mAccessibilityManager.isEnabled()) { - return; - } - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); - event.setClassName(Toast.class.getName()); - event.setPackageName(packageName); - view.dispatchPopulateAccessibilityEvent(event); - mAccessibilityManager.sendAccessibilityEvent(event); - } - - private View getView(CharSequence text) { - View view = LayoutInflater.from(mContext).inflate( - R.layout.transient_notification, null); - TextView textView = view.findViewById(com.android.internal.R.id.message); - textView.setText(text); - return view; - } - - private LayoutParams getLayoutParams(IBinder windowToken, int duration) { + private LayoutParams getLayoutParams(String packageName, IBinder windowToken, int duration) { WindowManager.LayoutParams params = new WindowManager.LayoutParams(); - params.height = WindowManager.LayoutParams.WRAP_CONTENT; - params.width = WindowManager.LayoutParams.WRAP_CONTENT; - params.format = PixelFormat.TRANSLUCENT; - params.windowAnimations = com.android.internal.R.style.Animation_Toast; - params.type = WindowManager.LayoutParams.TYPE_TOAST; - params.setTitle("Toast"); - params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; - Configuration config = mContext.getResources().getConfiguration(); - int specificGravity = mContext.getResources().getInteger( + mPresenter.startLayoutParams(params, packageName); + int gravity = mContext.getResources().getInteger( com.android.internal.R.integer.config_toastDefaultGravity); - int gravity = Gravity.getAbsoluteGravity(specificGravity, config.getLayoutDirection()); - params.gravity = gravity; - if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { - params.horizontalWeight = 1.0f; - } - if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { - params.verticalWeight = 1.0f; - } - params.x = 0; - params.y = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset); - params.verticalMargin = 0; - params.horizontalMargin = 0; - params.packageName = mContext.getPackageName(); - params.hideTimeoutMilliseconds = - (duration == Toast.LENGTH_LONG) ? DURATION_LONG : DURATION_SHORT; - params.token = windowToken; + int yOffset = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset); + mPresenter.adjustLayoutParams(params, windowToken, duration, gravity, 0, yOffset, 0, 0); return params; } diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index cfa2947eb862..5f821187e30c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -126,9 +126,10 @@ public class Utils { /** * Allow the media player to be shown in the QS area, controlled by 2 flags. + * On by default, but can be disabled by setting to 0 */ public static boolean useQsMediaPlayer(Context context) { - int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0); + int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 1); return flag > 0; } } diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java index b5bede4ad31c..13ba1a3cbf31 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java @@ -40,12 +40,11 @@ import javax.inject.Inject; */ public class ProximitySensor { private static final String TAG = "ProxSensor"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Sensor mSensor; private final AsyncSensorManager mSensorManager; - private final boolean mUsingBrightnessSensor; - private final float mMaxRange; + private final float mThreshold; private List<ProximitySensorListener> mListeners = new ArrayList<>(); private String mTag = null; @VisibleForTesting ProximityEvent mLastEvent; @@ -68,20 +67,27 @@ public class ProximitySensor { public ProximitySensor(@Main Resources resources, AsyncSensorManager sensorManager) { mSensorManager = sensorManager; - Sensor sensor = findBrightnessSensor(resources); + Sensor sensor = findCustomProxSensor(resources); + float threshold = 0; + if (sensor != null) { + try { + threshold = getCustomProxThreshold(resources); + } catch (IllegalStateException e) { + Log.e(TAG, "Can not load custom proximity sensor.", e); + sensor = null; + } + } if (sensor == null) { - mUsingBrightnessSensor = false; sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); - } else { - mUsingBrightnessSensor = true; + if (sensor != null) { + threshold = sensor.getMaximumRange(); + } } + + mThreshold = threshold; + mSensor = sensor; - if (mSensor != null) { - mMaxRange = mSensor.getMaximumRange(); - } else { - mMaxRange = 0; - } } public void setTag(String tag) { @@ -107,9 +113,15 @@ public class ProximitySensor { mPaused = false; registerInternal(); } + /** + * Returns a brightness sensor that can be used for proximity purposes. + */ + private Sensor findCustomProxSensor(Resources resources) { + String sensorType = resources.getString(R.string.proximity_sensor_type); + if (sensorType.isEmpty()) { + return null; + } - private Sensor findBrightnessSensor(Resources resources) { - String sensorType = resources.getString(R.string.doze_brightness_sensor_type); List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); Sensor sensor = null; for (Sensor s : sensorList) { @@ -123,6 +135,17 @@ public class ProximitySensor { } /** + * Returns a threshold value that can be used along with {@link #findCustomProxSensor} + */ + private float getCustomProxThreshold(Resources resources) { + try { + return resources.getFloat(R.dimen.proximity_sensor_threshold); + } catch (Resources.NotFoundException e) { + throw new IllegalStateException("R.dimen.proximity_sensor_threshold must be set."); + } + } + + /** * Returns true if we are registered with the SensorManager. */ public boolean isRegistered() { @@ -157,7 +180,6 @@ public class ProximitySensor { if (mRegistered || mPaused || mListeners.isEmpty()) { return; } - logDebug("Using brightness sensor? " + mUsingBrightnessSensor); logDebug("Registering sensor listener"); mRegistered = true; mSensorManager.registerListener(mSensorEventListener, mSensor, mSensorDelay); @@ -196,10 +218,7 @@ public class ProximitySensor { } private void onSensorEvent(SensorEvent event) { - boolean near = event.values[0] < mMaxRange; - if (mUsingBrightnessSensor) { - near = event.values[0] == 0; - } + boolean near = event.values[0] < mThreshold; mLastEvent = new ProximityEvent(near, event.timestamp); alertListeners(); } diff --git a/packages/SystemUI/src/com/android/systemui/util/time/DateFormatUtil.java b/packages/SystemUI/src/com/android/systemui/util/time/DateFormatUtil.java new file mode 100644 index 000000000000..d7c4e93bb26e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/time/DateFormatUtil.java @@ -0,0 +1,40 @@ +/* + * 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.systemui.util.time; + +import android.app.ActivityManager; +import android.content.Context; +import android.text.format.DateFormat; + +import javax.inject.Inject; + +/** + * Instantiable wrapper around {@link DateFormat}. + */ +public class DateFormatUtil { + private final Context mContext; + + @Inject + public DateFormatUtil(Context context) { + mContext = context; + } + + /** Returns true if the phone is in 24 hour format. */ + public boolean is24HourFormat() { + return DateFormat.is24HourFormat(mContext, ActivityManager.getCurrentUser()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index c912b678ac09..69e933e95562 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -16,6 +16,8 @@ package com.android.systemui; +import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static junit.framework.TestCase.fail; @@ -528,7 +530,8 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { .setSbn(notification) .build(), null, - false); + false, + REASON_APP_CANCEL); } private void entryAdded(StatusBarNotification notification, int importance) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java index 689eed9e2a61..678cfd23e3a5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java @@ -34,6 +34,7 @@ import android.graphics.Bitmap; import android.graphics.ColorSpace; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; +import android.os.Handler; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -72,6 +73,8 @@ public class ImageWallpaperTest extends SysuiTestCase { private Bitmap mWallpaperBitmap; @Mock private DozeParameters mDozeParam; + @Mock + private Handler mHandler; private CountDownLatch mEventCountdown; @@ -104,7 +107,7 @@ public class ImageWallpaperTest extends SysuiTestCase { return new ImageWallpaper(mDozeParam) { @Override public Engine onCreateEngine() { - return new GLEngine(mMockContext, mDozeParam) { + return new GLEngine(mDozeParam, mHandler) { @Override public Context getDisplayContext() { return mMockContext; @@ -196,5 +199,6 @@ public class ImageWallpaperTest extends SysuiTestCase { when(mSurfaceHolder.getSurfaceFrame()).thenReturn(frame); assertThat(engineSpy.checkIfShouldStopTransition()).isEqualTo(assertion); + // destroy } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index a974c6d0e5b5..1b34b3d85c09 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -456,4 +456,52 @@ public class ScreenDecorationsTest extends SysuiTestCase { assertThat(rectsToRegion(Collections.singletonList(rect)).getBounds(), is(rect)); } + @Test + public void testRegistration_From_NoOverlay_To_HasOverlays() { + doReturn(false).when(mScreenDecorations).hasOverlays(); + mScreenDecorations.start(); + verify(mTunerService, times(0)).addTunable(any(), any()); + verify(mTunerService, times(1)).removeTunable(any()); + assertThat(mScreenDecorations.mIsRegistered, is(false)); + reset(mTunerService); + + doReturn(true).when(mScreenDecorations).hasOverlays(); + mScreenDecorations.onConfigurationChanged(new Configuration()); + verify(mTunerService, times(1)).addTunable(any(), any()); + verify(mTunerService, times(0)).removeTunable(any()); + assertThat(mScreenDecorations.mIsRegistered, is(true)); + } + + @Test + public void testRegistration_From_HasOverlays_To_HasOverlays() { + doReturn(true).when(mScreenDecorations).hasOverlays(); + + mScreenDecorations.start(); + verify(mTunerService, times(1)).addTunable(any(), any()); + verify(mTunerService, times(0)).removeTunable(any()); + assertThat(mScreenDecorations.mIsRegistered, is(true)); + reset(mTunerService); + + mScreenDecorations.onConfigurationChanged(new Configuration()); + verify(mTunerService, times(0)).addTunable(any(), any()); + verify(mTunerService, times(0)).removeTunable(any()); + assertThat(mScreenDecorations.mIsRegistered, is(true)); + } + + @Test + public void testRegistration_From_HasOverlays_To_NoOverlay() { + doReturn(true).when(mScreenDecorations).hasOverlays(); + + mScreenDecorations.start(); + verify(mTunerService, times(1)).addTunable(any(), any()); + verify(mTunerService, times(0)).removeTunable(any()); + assertThat(mScreenDecorations.mIsRegistered, is(true)); + reset(mTunerService); + + doReturn(false).when(mScreenDecorations).hasOverlays(); + mScreenDecorations.onConfigurationChanged(new Configuration()); + verify(mTunerService, times(0)).addTunable(any(), any()); + verify(mTunerService, times(1)).removeTunable(any()); + assertThat(mScreenDecorations.mIsRegistered, is(false)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index 7ac5443d67d0..a36f2c754243 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -86,7 +86,9 @@ public abstract class SysuiTestCase { public void SysuiTeardown() { InstrumentationRegistry.registerInstance(mRealInstrumentation, InstrumentationRegistry.getArguments()); - // Reset the assert's testable looper to null. + if (TestableLooper.get(this) != null) { + TestableLooper.get(this).processAllMessages(); + } disallowTestableLooperAsMainThread(); SystemUIFactory.cleanup(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 30095935aed5..9fe9e6de7996 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -685,7 +685,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleController.hasBubbles()); // Removes the notification - mEntryListener.onEntryRemoved(mRow.getEntry(), null, false); + mEntryListener.onEntryRemoved(mRow.getEntry(), null, false, REASON_APP_CANCEL); assertFalse(mBubbleController.hasBubbles()); } @@ -827,7 +827,7 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.handleDismissalInterception(groupSummary.getEntry()); // WHEN the summary is cancelled by the app - mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, true); + mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, false, REASON_APP_CANCEL); // THEN the summary and its children are removed from bubble data assertFalse(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey())); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java index 545d2d4229b3..5b78067ef81a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java @@ -33,7 +33,9 @@ import com.android.systemui.classifier.brightline.BrightLineFalsingManager; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerFake; import com.android.systemui.dump.DumpManager; +import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; @@ -63,6 +65,7 @@ public class FalsingManagerProxyTest extends SysuiTestCase { private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private DockManager mDockManager = new DockManagerFake(); + private StatusBarStateController mStatusBarStateController = new StatusBarStateControllerImpl(); @Before public void setup() { @@ -83,7 +86,7 @@ public class FalsingManagerProxyTest extends SysuiTestCase { public void test_brightLineFalsingManagerDisabled() { mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics, mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor, - mDumpManager, mUiBgExecutor); + mDumpManager, mUiBgExecutor, mStatusBarStateController); assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class)); } @@ -94,7 +97,7 @@ public class FalsingManagerProxyTest extends SysuiTestCase { mExecutor.runAllReady(); mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics, mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor, - mDumpManager, mUiBgExecutor); + mDumpManager, mUiBgExecutor, mStatusBarStateController); assertThat(mProxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class)); } @@ -102,7 +105,7 @@ public class FalsingManagerProxyTest extends SysuiTestCase { public void test_brightLineFalsingManagerToggled() throws InterruptedException { mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics, mProximitySensor, mDeviceConfig, mDockManager, mKeyguardUpdateMonitor, - mDumpManager, mUiBgExecutor); + mDumpManager, mUiBgExecutor, mStatusBarStateController); assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class)); mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java index 0aaa3b6ad329..8b5cc9abb777 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/BrightLineFalsingManagerTest.java @@ -22,12 +22,16 @@ import static org.mockito.Mockito.verify; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.util.DisplayMetrics; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerFake; +import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.StatusBarStateControllerImpl; +import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.sensors.ProximitySensor; @@ -40,6 +44,7 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper public class BrightLineFalsingManagerTest extends SysuiTestCase { @@ -47,6 +52,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private ProximitySensor mProximitySensor; + private SysuiStatusBarStateController mStatusBarStateController; private BrightLineFalsingManager mFalsingManager; @@ -61,8 +67,11 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { FalsingDataProvider falsingDataProvider = new FalsingDataProvider(dm); DeviceConfigProxy deviceConfigProxy = new DeviceConfigProxyFake(); DockManager dockManager = new DockManagerFake(); + mStatusBarStateController = new StatusBarStateControllerImpl(); + mStatusBarStateController.setState(StatusBarState.KEYGUARD); mFalsingManager = new BrightLineFalsingManager(falsingDataProvider, - mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, dockManager); + mKeyguardUpdateMonitor, mProximitySensor, deviceConfigProxy, dockManager, + mStatusBarStateController); } @Test @@ -98,4 +107,12 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { mFalsingManager.onBouncerHidden(); verify(mProximitySensor).register(any(ProximitySensor.ProximitySensorListener.class)); } + + @Test + public void testUnregisterSensor_StateTransition() { + mFalsingManager.onScreenTurningOn(); + reset(mProximitySensor); + mStatusBarStateController.setState(StatusBarState.SHADE); + verify(mProximitySensor).unregister(any(ProximitySensor.ProximitySensorListener.class)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt new file mode 100644 index 000000000000..68e1ec1d9f1d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.management + +import android.app.PendingIntent +import android.service.controls.Control +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.controls.ControlStatus +import com.android.systemui.controls.controller.ControlInfo +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class AllModelTest : SysuiTestCase() { + + companion object { + private const val EMPTY_STRING = "Other" + } + + @Mock + lateinit var pendingIntent: PendingIntent + + val idPrefix = "controlId" + val favoritesIndices = listOf(7, 3, 1, 9) + val favoritesList = favoritesIndices.map { "controlId$it" } + lateinit var controls: List<ControlStatus> + + lateinit var model: AllModel + + private fun zoneMap(id: Int): String? { + return when (id) { + 10 -> "" + 11 -> null + else -> ((id + 1) % 3).toString() + } + } + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + // controlId0 --> zone = 1 + // controlId1 --> zone = 2, favorite + // controlId2 --> zone = 0 + // controlId3 --> zone = 1, favorite + // controlId4 --> zone = 2 + // controlId5 --> zone = 0 + // controlId6 --> zone = 1 + // controlId7 --> zone = 2, favorite + // controlId8 --> zone = 0 + // controlId9 --> zone = 1, favorite + // controlId10 --> zone = "" + // controlId11 --> zone = null + controls = (0..11).map { + ControlStatus( + Control.StatelessBuilder("$idPrefix$it", pendingIntent) + .setZone(zoneMap(it)) + .build(), + it in favoritesIndices + ) + } + model = AllModel(controls, favoritesList, EMPTY_STRING) + } + + @Test + fun testElements() { + + // Zones are sorted by order of appearance, with empty at the end with special header. + val expected = listOf( + ZoneNameWrapper("1"), + ControlWrapper(controls[0]), + ControlWrapper(controls[3]), + ControlWrapper(controls[6]), + ControlWrapper(controls[9]), + ZoneNameWrapper("2"), + ControlWrapper(controls[1]), + ControlWrapper(controls[4]), + ControlWrapper(controls[7]), + ZoneNameWrapper("0"), + ControlWrapper(controls[2]), + ControlWrapper(controls[5]), + ControlWrapper(controls[8]), + ZoneNameWrapper(EMPTY_STRING), + ControlWrapper(controls[10]), + ControlWrapper(controls[11]) + ) + expected.zip(model.elements).forEachIndexed { index, it -> + assertEquals("Error in item at index $index", it.first, it.second) + } + } + + private fun sameControl(controlInfo: ControlInfo.Builder, control: Control): Boolean { + return controlInfo.controlId == control.controlId && + controlInfo.controlTitle == control.title && + controlInfo.deviceType == control.deviceType + } + + @Test + fun testAllEmpty_noHeader() { + val selected_controls = listOf(controls[10], controls[11]) + val new_model = AllModel(selected_controls, emptyList(), EMPTY_STRING) + val expected = listOf( + ControlWrapper(controls[10]), + ControlWrapper(controls[11]) + ) + + expected.zip(new_model.elements).forEachIndexed { index, it -> + assertEquals("Error in item at index $index", it.first, it.second) + } + } + + @Test + fun testFavorites() { + val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control) + model.favorites.zip(expectedFavorites).forEach { + assertTrue(sameControl(it.first, it.second)) + } + } + + @Test + fun testAddFavorite() { + val indexToAdd = 6 + model.changeFavoriteStatus("$idPrefix$indexToAdd", true) + + val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control) + + controls[indexToAdd].control + + model.favorites.zip(expectedFavorites).forEach { + assertTrue(sameControl(it.first, it.second)) + } + } + + @Test + fun testAddFavorite_alreadyThere() { + val indexToAdd = 7 + model.changeFavoriteStatus("$idPrefix$indexToAdd", true) + + val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control) + + model.favorites.zip(expectedFavorites).forEach { + assertTrue(sameControl(it.first, it.second)) + } + } + + @Test + fun testRemoveFavorite() { + val indexToRemove = 3 + model.changeFavoriteStatus("$idPrefix$indexToRemove", false) + + val expectedFavorites = (favoritesIndices.filterNot { it == indexToRemove }) + .map(controls::get) + .map(ControlStatus::control) + + model.favorites.zip(expectedFavorites).forEach { + assertTrue(sameControl(it.first, it.second)) + } + } + + @Test + fun testRemoveFavorite_notThere() { + val indexToRemove = 4 + model.changeFavoriteStatus("$idPrefix$indexToRemove", false) + + val expectedFavorites = favoritesIndices.map(controls::get).map(ControlStatus::control) + + model.favorites.zip(expectedFavorites).forEach { + assertTrue(sameControl(it.first, it.second)) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 9ef5520ee711..8320b058208c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -44,6 +44,8 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -69,6 +71,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock DumpManager mDumpManager; private @Mock PowerManager mPowerManager; private @Mock TrustManager mTrustManager; + private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private FalsingManagerFake mFalsingManager; @@ -85,7 +88,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher, mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, - mPowerManager, mTrustManager); + mPowerManager, mTrustManager, mDeviceConfig); mViewMediator.start(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java index 1dbcf10d08d6..3b00684786b8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java @@ -16,6 +16,7 @@ package com.android.systemui.pip; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.content.ComponentName; @@ -44,8 +45,11 @@ import org.junit.runner.RunWith; @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) public class PipBoundsHandlerTest extends SysuiTestCase { - private static final int ROUNDING_ERROR_MARGIN = 10; + private static final int ROUNDING_ERROR_MARGIN = 16; + private static final float ASPECT_RATIO_ERROR_MARGIN = 0.01f; private static final float DEFAULT_ASPECT_RATIO = 1f; + private static final float MIN_ASPECT_RATIO = 0.5f; + private static final float MAX_ASPECT_RATIO = 2f; private static final Rect EMPTY_CURRENT_BOUNDS = null; private PipBoundsHandler mPipBoundsHandler; @@ -53,8 +57,8 @@ public class PipBoundsHandlerTest extends SysuiTestCase { @Before public void setUp() throws Exception { - mPipBoundsHandler = new PipBoundsHandler(mContext); initializeMockResources(); + mPipBoundsHandler = new PipBoundsHandler(mContext); mPipBoundsHandler.onDisplayInfoChanged(mDefaultDisplayInfo); } @@ -62,7 +66,8 @@ public class PipBoundsHandlerTest extends SysuiTestCase { private void initializeMockResources() { final TestableResources res = mContext.getOrCreateTestableResources(); res.addOverride( - com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio, 1f); + com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio, + DEFAULT_ASPECT_RATIO); res.addOverride( com.android.internal.R.integer.config_defaultPictureInPictureGravity, Gravity.END | Gravity.BOTTOM); @@ -72,9 +77,11 @@ public class PipBoundsHandlerTest extends SysuiTestCase { com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets, "16x16"); res.addOverride( - com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio, 0.5f); + com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio, + MIN_ASPECT_RATIO); res.addOverride( - com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio, 2f); + com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio, + MAX_ASPECT_RATIO); mDefaultDisplayInfo = new DisplayInfo(); mDefaultDisplayInfo.displayId = 1; @@ -83,6 +90,76 @@ public class PipBoundsHandlerTest extends SysuiTestCase { } @Test + public void getDefaultAspectRatio() { + assertEquals("Default aspect ratio matches resources", + DEFAULT_ASPECT_RATIO, mPipBoundsHandler.getDefaultAspectRatio(), + ASPECT_RATIO_ERROR_MARGIN); + } + + @Test + public void onConfigurationChanged_reloadResources() { + final float newDefaultAspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2; + final TestableResources res = mContext.getOrCreateTestableResources(); + res.addOverride(com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio, + newDefaultAspectRatio); + + mPipBoundsHandler.onConfigurationChanged(); + + assertEquals("Default aspect ratio should be reloaded", + mPipBoundsHandler.getDefaultAspectRatio(), newDefaultAspectRatio, + ASPECT_RATIO_ERROR_MARGIN); + } + + @Test + public void getDestinationBounds_returnBoundsMatchesAspectRatio() { + final float[] aspectRatios = new float[] { + (MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2, + DEFAULT_ASPECT_RATIO, + (MAX_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2 + }; + for (float aspectRatio : aspectRatios) { + final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( + aspectRatio, EMPTY_CURRENT_BOUNDS); + final float actualAspectRatio = + destinationBounds.width() / (destinationBounds.height() * 1f); + assertEquals("Destination bounds matches the given aspect ratio", + aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN); + } + } + + @Test + public void getDestinationBounds_invalidAspectRatio_returnsDefaultAspectRatio() { + final float[] invalidAspectRatios = new float[] { + MIN_ASPECT_RATIO / 2, + MAX_ASPECT_RATIO * 2 + }; + for (float aspectRatio : invalidAspectRatios) { + final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( + aspectRatio, EMPTY_CURRENT_BOUNDS); + final float actualAspectRatio = + destinationBounds.width() / (destinationBounds.height() * 1f); + assertEquals("Destination bounds fallbacks to default aspect ratio", + mPipBoundsHandler.getDefaultAspectRatio(), actualAspectRatio, + ASPECT_RATIO_ERROR_MARGIN); + } + } + + @Test + public void getDestinationBounds_withCurrentBounds_returnBoundsMatchesAspectRatio() { + final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2; + final Rect currentBounds = new Rect(0, 0, 0, 100); + currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left; + + final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( + aspectRatio, currentBounds); + + final float actualAspectRatio = + destinationBounds.width() / (destinationBounds.height() * 1f); + assertEquals("Destination bounds matches the given aspect ratio", + aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN); + } + + @Test public void setShelfHeight_offsetBounds() { final int shelfHeight = 100; final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( @@ -93,7 +170,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); oldPosition.offset(0, -shelfHeight); - assertBoundsWithMargin("PiP bounds offset by shelf height", oldPosition, newPosition); + assertBoundsWithMargin("offsetBounds by shelf", oldPosition, newPosition); } @Test @@ -107,7 +184,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); oldPosition.offset(0, -imeHeight); - assertBoundsWithMargin("PiP bounds offset by IME height", oldPosition, newPosition); + assertBoundsWithMargin("offsetBounds by IME", oldPosition, newPosition); } @Test @@ -122,11 +199,11 @@ public class PipBoundsHandlerTest extends SysuiTestCase { final Rect newPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); - assertBoundsWithMargin("Last position is restored", oldPosition, newPosition); + assertBoundsWithMargin("restoreLastPosition", oldPosition, newPosition); } @Test - public void onResetReentryBounds_componentMatch_useDefaultBounds() { + public void onResetReentryBounds_useDefaultBounds() { final ComponentName componentName = new ComponentName(mContext, "component1"); final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); @@ -138,7 +215,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); - assertBoundsWithMargin("Use default bounds", defaultBounds, actualBounds); + assertBoundsWithMargin("useDefaultBounds", defaultBounds, actualBounds); } @Test @@ -154,11 +231,15 @@ public class PipBoundsHandlerTest extends SysuiTestCase { final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); - assertBoundsWithMargin("Last position is restored", newBounds, actualBounds); + assertBoundsWithMargin("restoreLastPosition", newBounds, actualBounds); } - private void assertBoundsWithMargin(String msg, Rect expected, Rect actual) { - expected.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN); - assertTrue(msg, expected.contains(actual)); + private void assertBoundsWithMargin(String from, Rect expected, Rect actual) { + final Rect expectedWithMargin = new Rect(expected); + expectedWithMargin.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN); + assertTrue(from + ": expect " + expected + + " contains " + actual + + " with error margin " + ROUNDING_ERROR_MARGIN, + expectedWithMargin.contains(actual)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 36a9ea6de5aa..00980129cf74 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Handler; @@ -76,7 +77,9 @@ import javax.inject.Provider; public class QSTileHostTest extends SysuiTestCase { private static String MOCK_STATE_STRING = "MockState"; - private static final String CUSTOM_TILE_SPEC = "custom(TEST_PKG/.TEST_CLS)"; + private static ComponentName CUSTOM_TILE = + ComponentName.unflattenFromString("TEST_PKG/.TEST_CLS"); + private static final String CUSTOM_TILE_SPEC = CustomTile.toSpec(CUSTOM_TILE); @Mock private StatusBarIconController mIconController; @@ -114,24 +117,30 @@ public class QSTileHostTest extends SysuiTestCase { mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, mBroadcastDispatcher, mStatusBar, mQSLogger); setUpTileFactory(); + + // Override this config so there are no unexpected tiles + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.string.config_defaultExtraQuickSettingsTiles, + ""); + Settings.Secure.putStringForUser(mContext.getContentResolver(), QSTileHost.TILES_SETTING, "", ActivityManager.getCurrentUser()); } private void setUpTileFactory() { when(mMockState.toString()).thenReturn(MOCK_STATE_STRING); + // Only create this kind of tiles when(mDefaultFactory.createTile(anyString())).thenAnswer( invocation -> { String spec = invocation.getArgument(0); - switch (spec) { - case "spec1": - return new TestTile1(mQSTileHost); - case "spec2": - return new TestTile2(mQSTileHost); - case CUSTOM_TILE_SPEC: - return mCustomTile; - default: - return null; + if ("spec1".equals(spec)) { + return new TestTile1(mQSTileHost); + } else if ("spec2".equals(spec)) { + return new TestTile2(mQSTileHost); + } else if (CUSTOM_TILE_SPEC.equals(spec)) { + return mCustomTile; + } else { + return null; } }); when(mCustomTile.isAvailable()).thenReturn(true); @@ -222,6 +231,58 @@ public class QSTileHostTest extends SysuiTestCase { verify(mQSLogger).logTileAdded(CUSTOM_TILE_SPEC); } + @Test + public void testNoRepeatedSpecs_addTile() { + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + + mQSTileHost.addTile("spec1"); + + assertEquals(2, mQSTileHost.mTileSpecs.size()); + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + } + + @Test + public void testNoRepeatedSpecs_customTile() { + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, CUSTOM_TILE_SPEC); + + mQSTileHost.addTile(CUSTOM_TILE); + + assertEquals(1, mQSTileHost.mTileSpecs.size()); + assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0)); + } + + @Test + public void testLoadTileSpec_repeated() { + List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2"); + + assertEquals(2, specs.size()); + assertEquals("spec1", specs.get(0)); + assertEquals("spec2", specs.get(1)); + } + + @Test + public void testLoadTileSpec_repeatedInDefault() { + mContext.getOrCreateTestableResources() + .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default"); + + // Remove spurious tiles, like dbg:mem + specs.removeIf(spec -> !"spec1".equals(spec)); + assertEquals(1, specs.size()); + } + + @Test + public void testLoadTileSpec_repeatedDefaultAndSetting() { + mContext.getOrCreateTestableResources() + .addOverride(R.string.quick_settings_tiles_default, "spec1"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1"); + + // Remove spurious tiles, like dbg:mem + specs.removeIf(spec -> !"spec1".equals(spec)); + assertEquals(1, specs.size()); + } + private static class TestQSTileHost extends QSTileHost { TestQSTileHost(Context context, StatusBarIconController iconController, QSFactoryImpl defaultFactory, Handler mainHandler, Looper bgLooper, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt index 9fe2569177d7..58be50e1e66d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.QSTileHost import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -84,13 +85,26 @@ class CustomTileTest : SysuiTestCase() { .thenReturn(mServiceInfo) mServiceInfo.applicationInfo = mApplicationInfo - customTile = CustomTile.create(mTileHost, TILE_SPEC) + customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext) + } + + @Test + fun testCorrectUser() { + assertEquals(0, customTile.user) + + val userContext = mock(Context::class.java) + `when`(userContext.packageManager).thenReturn(mPackageManager) + `when`(userContext.userId).thenReturn(10) + + val tile = CustomTile.create(mTileHost, TILE_SPEC, userContext) + + assertEquals(10, tile.user) } @Test fun testToggleableTileHasBooleanState() { `when`(mTileServiceManager.isToggleableTile).thenReturn(true) - customTile = CustomTile.create(mTileHost, TILE_SPEC) + customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext) assertTrue(customTile.state is QSTile.BooleanState) assertTrue(customTile.newTileState() is QSTile.BooleanState) @@ -105,7 +119,7 @@ class CustomTileTest : SysuiTestCase() { @Test fun testValueUpdatedInBooleanTile() { `when`(mTileServiceManager.isToggleableTile).thenReturn(true) - customTile = CustomTile.create(mTileHost, TILE_SPEC) + customTile = CustomTile.create(mTileHost, TILE_SPEC, mContext) customTile.qsTile.icon = mock(Icon::class.java) `when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java))) .thenReturn(mock(Drawable::class.java)) @@ -125,4 +139,12 @@ class CustomTileTest : SysuiTestCase() { customTile.handleUpdateState(state, null) assertFalse(state.value) } + + @Test + fun testNoCrashOnNullDrawable() { + customTile.qsTile.icon = mock(Icon::class.java) + `when`(customTile.qsTile.icon.loadDrawable(any(Context::class.java))) + .thenReturn(null) + customTile.handleUpdateState(customTile.newTileState(), null) + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 8e87e0a802ef..cc5f149eabd3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -41,11 +41,11 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; +import com.android.systemui.statusbar.notification.DynamicChildBindController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; @@ -106,17 +106,14 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mock(KeyguardBypassController.class), mock(BubbleController.class), mock(DynamicPrivacyController.class), - mock(ForegroundServiceSectionController.class)); + mock(ForegroundServiceSectionController.class), + mock(DynamicChildBindController.class)); mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer); } private NotificationEntry createEntry() throws Exception { ExpandableNotificationRow row = mHelper.createRow(); - NotificationEntry entry = new NotificationEntryBuilder() - .setSbn(row.getEntry().getSbn()) - .build(); - entry.setRow(row); - return entry; + return row.getEntry(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java index 16f105d5a08c..fe8b89f381d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager.Importance; +import android.content.pm.ShortcutInfo; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.SnoozeCriterion; @@ -53,6 +54,7 @@ public class RankingBuilder { private boolean mCanBubble = false; private boolean mIsVisuallyInterruptive = false; private boolean mIsConversation = false; + private ShortcutInfo mShortcutInfo = null; public RankingBuilder() { } @@ -79,6 +81,7 @@ public class RankingBuilder { mCanBubble = ranking.canBubble(); mIsVisuallyInterruptive = ranking.visuallyInterruptive(); mIsConversation = ranking.isConversation(); + mShortcutInfo = ranking.getShortcutInfo(); } public Ranking build() { @@ -104,7 +107,8 @@ public class RankingBuilder { mSmartReplies, mCanBubble, mIsVisuallyInterruptive, - mIsConversation); + mIsConversation, + mShortcutInfo); return ranking; } @@ -189,6 +193,11 @@ public class RankingBuilder { return this; } + public RankingBuilder setShortcutInfo(ShortcutInfo shortcutInfo) { + mShortcutInfo = shortcutInfo; + return this; + } + public RankingBuilder setImportance(@Importance int importance) { mImportance = importance; return this; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java index 62f406ff835a..742dfee9460a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java @@ -22,6 +22,8 @@ import android.content.Context; import android.os.UserHandle; import android.service.notification.StatusBarNotification; +import com.android.internal.logging.InstanceId; + /** * Convenience builder for {@link StatusBarNotification} since its constructor is terrifying. * @@ -40,6 +42,7 @@ public class SbnBuilder { private UserHandle mUser = UserHandle.of(0); private String mOverrideGroupKey; private long mPostTime; + private InstanceId mInstanceId; public SbnBuilder() { } @@ -55,6 +58,7 @@ public class SbnBuilder { mUser = source.getUser(); mOverrideGroupKey = source.getOverrideGroupKey(); mPostTime = source.getPostTime(); + mInstanceId = source.getInstanceId(); } public StatusBarNotification build() { @@ -71,7 +75,7 @@ public class SbnBuilder { notification.setBubbleMetadata(mBubbleMetadata); } - return new StatusBarNotification( + StatusBarNotification result = new StatusBarNotification( mPkg, mOpPkg, mId, @@ -82,6 +86,12 @@ public class SbnBuilder { mUser, mOverrideGroupKey, mPostTime); + if (mInstanceId != null) { + result.setInstanceId(mInstanceId); + } else { + result.setInstanceId(InstanceId.fakeInstanceId(1)); + } + return result; } public SbnBuilder setPkg(String pkg) { @@ -175,4 +185,9 @@ public class SbnBuilder { mBubbleMetadata = data; return this; } + + public SbnBuilder setInstanceId(InstanceId instanceId) { + mInstanceId = instanceId; + return this; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java new file mode 100644 index 000000000000..bf2d59880ffb --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java @@ -0,0 +1,133 @@ +/* + * 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.systemui.statusbar.notification; + +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.ArrayMap; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.RowContentBindParams; +import com.android.systemui.statusbar.notification.row.RowContentBindStage; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DynamicChildBindControllerTest extends SysuiTestCase { + + private DynamicChildBindController mDynamicChildBindController; + private Map<NotificationEntry, List<NotificationEntry>> mGroupNotifs = new ArrayMap<>(); + private static final int TEST_CHILD_BIND_CUTOFF = 5; + + @Mock private RowContentBindStage mBindStage; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + allowTestableLooperAsMainThread(); + when(mBindStage.getStageParams(any())).thenReturn(new RowContentBindParams()); + mDynamicChildBindController = + new DynamicChildBindController(mBindStage, TEST_CHILD_BIND_CUTOFF); + } + + @Test + public void testContentViewsOfChildrenBeyondCutoffAreFreed() { + // GIVEN a group notification with one view beyond the cutoff with content bound + NotificationEntry summary = addGroup(TEST_CHILD_BIND_CUTOFF + 1); + NotificationEntry lastChild = mGroupNotifs.get(summary).get(TEST_CHILD_BIND_CUTOFF); + + RowContentBindParams bindParams = mock(RowContentBindParams.class); + when(mBindStage.getStageParams(lastChild)).thenReturn(bindParams); + + // WHEN the controller gets the list + mDynamicChildBindController.updateChildContentViews(mGroupNotifs); + + // THEN we free content views + verify(bindParams).freeContentViews(FLAG_CONTENT_VIEW_CONTRACTED); + verify(bindParams).freeContentViews(FLAG_CONTENT_VIEW_EXPANDED); + verify(mBindStage).requestRebind(eq(lastChild), any()); + } + + @Test + public void testContentViewsBeforeCutoffAreBound() { + // GIVEN a group notification with one view before the cutoff with content unbound + NotificationEntry summary = addGroup(TEST_CHILD_BIND_CUTOFF); + NotificationEntry lastChild = mGroupNotifs.get(summary).get(TEST_CHILD_BIND_CUTOFF - 1); + + lastChild.getRow().getPrivateLayout().setContractedChild(null); + lastChild.getRow().getPrivateLayout().setExpandedChild(null); + + RowContentBindParams bindParams = mock(RowContentBindParams.class); + when(mBindStage.getStageParams(lastChild)).thenReturn(bindParams); + + // WHEN the controller gets the list + mDynamicChildBindController.updateChildContentViews(mGroupNotifs); + + // THEN we bind content views + verify(bindParams).requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED); + verify(bindParams).requireContentViews(FLAG_CONTENT_VIEW_EXPANDED); + verify(mBindStage).requestRebind(eq(lastChild), any()); + } + + private NotificationEntry addGroup(int size) { + NotificationEntry summary = new NotificationEntryBuilder().build(); + summary.setRow(createRow()); + ArrayList<NotificationEntry> children = new ArrayList<>(); + for (int i = 0; i < size; i++) { + NotificationEntry child = new NotificationEntryBuilder().build(); + child.setRow(createRow()); + children.add(child); + } + mGroupNotifs.put(summary, children); + return summary; + } + + private ExpandableNotificationRow createRow() { + ExpandableNotificationRow row = (ExpandableNotificationRow) + LayoutInflater.from(mContext).inflate(R.layout.status_bar_notification_row, null); + row.getPrivateLayout().setContractedChild(new View(mContext)); + row.getPrivateLayout().setExpandedChild(new View(mContext)); + return row; + } +} + diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 98f12ce06e49..312bb7f08e72 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -143,7 +143,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { IMPORTANCE_DEFAULT, null, null, null, null, null, true, sentiment, false, -1, false, null, null, false, false, - false); + false, null); return true; }).when(mRankingMap).getRanking(eq(key), any(Ranking.class)); } @@ -162,7 +162,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { null, null, null, null, null, true, Ranking.USER_SENTIMENT_NEUTRAL, false, -1, - false, smartActions, null, false, false, false); + false, smartActions, null, false, false, false, null); return true; }).when(mRankingMap).getRanking(eq(key), any(Ranking.class)); } @@ -254,7 +254,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mPresenter).updateNotificationViews(); verify(mEntryListener).onEntryRemoved( - eq(mEntry), any(), eq(false) /* removedByUser */); + eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON)); verify(mRow).setRemoved(); assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); @@ -266,7 +266,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON); verify(mEntryListener, never()).onEntryRemoved( - eq(mEntry), any(), eq(false) /* removedByUser */); + eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON)); } @Test @@ -275,7 +275,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); verify(mEntryListener, never()).onEntryRemoved( - eq(mEntry), any(), eq(false /* removedByUser */)); + eq(mEntry), any(), eq(false /* removedByUser */), eq(UNDEFINED_DISMISS_REASON)); } @Test @@ -356,7 +356,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(extender).setShouldManageLifetime(mEntry, true); // THEN the notification is retained assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); - verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), any(), eq(false)); + verify(mEntryListener, never()).onEntryRemoved( + eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON)); } @Test @@ -374,7 +375,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase { // THEN the notification is removed assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); - verify(mEntryListener).onEntryRemoved(eq(mEntry), any(), eq(false)); + verify(mEntryListener).onEntryRemoved( + eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON)); } @Test @@ -447,7 +449,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { // THEN the interceptor intercepts & the entry is not removed & no listeners are called assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), - any(NotificationVisibility.class), anyBoolean()); + any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON)); } @Test @@ -466,7 +468,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { // THEN the interceptor intercepts & the entry is not removed & no listeners are called assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey())); verify(mEntryListener, atLeastOnce()).onEntryRemoved(eq(mEntry), - any(NotificationVisibility.class), anyBoolean()); + any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON)); } private NotificationEntry createNotification() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java index 7343e5e9e07d..19dd027daedd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification; +import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; + import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; @@ -87,7 +89,8 @@ public class NotificationListControllerTest extends SysuiTestCase { mEntryListener.onEntryRemoved( entry, NotificationVisibility.obtain(entry.getKey(), 0, 0, true), - false); + false, + UNDEFINED_DISMISS_REASON); verify(mListContainer).cleanUpViewStateForEntry(entry); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java index d2bb0119c0b3..92a908033472 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java @@ -21,6 +21,7 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; +import android.content.pm.ShortcutInfo; import android.os.UserHandle; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; @@ -266,4 +267,9 @@ public class NotificationEntryBuilder { mRankingBuilder.setSmartReplies(smartReplies); return this; } + + public NotificationEntryBuilder setShortcutInfo(ShortcutInfo shortcutInfo) { + mRankingBuilder.setShortcutInfo(shortcutInfo); + return this; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt index f37836c7a506..5a6f888b53ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager import dagger.Lazy import junit.framework.Assert.assertEquals import org.junit.Before +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock @@ -195,6 +196,7 @@ class NotificationRankingManagerTest : SysuiTestCase() { assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test")) } + @Ignore // TODO: (b/149046729) fix test and re-enable @Test fun testSort_importantPeople() { whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java index d826ce1bbdd8..79ba13681521 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java @@ -16,7 +16,10 @@ package com.android.systemui.statusbar.notification.logging; +import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING; + import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; @@ -62,6 +65,8 @@ import org.mockito.MockitoAnnotations; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; +import nano.Notifications; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -81,9 +86,10 @@ public class NotificationLoggerTest extends SysuiTestCase { private NotificationEntry mEntry; private TestableNotificationLogger mLogger; - private NotificationEntryListener mNotificationEntryListener; private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); + private NotificationPanelLoggerFake mNotificationPanelLoggerFake = + new NotificationPanelLoggerFake(); @Before public void setUp() { @@ -105,7 +111,6 @@ public class NotificationLoggerTest extends SysuiTestCase { mExpansionStateLogger); mLogger.setUpWithContainer(mListContainer); verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture()); - mNotificationEntryListener = mEntryListenerCaptor.getValue(); } @Test @@ -164,6 +169,21 @@ public class NotificationLoggerTest extends SysuiTestCase { verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any()); } + @Test + public void testLogPanelShownOnLoggingStart() { + when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry)); + mLogger.startNotificationLogging(); + assertEquals(1, mNotificationPanelLoggerFake.getCalls().size()); + assertEquals(false, mNotificationPanelLoggerFake.get(0).isDozing); + assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length); + Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0]; + assertEquals(TEST_PACKAGE_NAME, n.packageName); + assertEquals(TEST_UID, n.uid); + assertEquals(1, n.instanceId); + assertEquals(false, n.isGroupSummary); + assertEquals(1 + BUCKET_ALERTING, n.section); + } + private class TestableNotificationLogger extends NotificationLogger { TestableNotificationLogger(NotificationListener notificationListener, @@ -173,7 +193,7 @@ public class NotificationLoggerTest extends SysuiTestCase { IStatusBarService barService, ExpansionStateLogger expansionStateLogger) { super(notificationListener, uiBgExecutor, entryManager, statusBarStateController, - expansionStateLogger); + expansionStateLogger, mNotificationPanelLoggerFake); mBarService = barService; // Make this on the current thread so we can wait for it during tests. mHandler = Handler.createAsync(Looper.myLooper()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java new file mode 100644 index 000000000000..551f3977e968 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java @@ -0,0 +1,52 @@ +/* + * 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.systemui.statusbar.notification.logging; + +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import java.util.ArrayList; +import java.util.List; + +import nano.Notifications; + +public class NotificationPanelLoggerFake implements NotificationPanelLogger { + private List<CallRecord> mCalls = new ArrayList<>(); + + List<CallRecord> getCalls() { + return mCalls; + } + + CallRecord get(int index) { + return mCalls.get(index); + } + + @Override + public void logPanelShown(boolean isLockscreen, + List<NotificationEntry> visibleNotifications) { + mCalls.add(new CallRecord(isLockscreen, + NotificationPanelLogger.toNotificationProto(visibleNotifications))); + } + + public static class CallRecord { + public boolean isDozing; + public Notifications.NotificationList list; + CallRecord(boolean isDozing, Notifications.NotificationList list) { + this.isDozing = isDozing; + this.list = list; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt index b0ca943bd6be..b1288f8c33f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt @@ -101,15 +101,13 @@ class PeopleHubViewControllerTest : SysuiTestCase() { @Test fun testViewModelDataSourceTransformsModel() { - val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0) - val fakePerson = fakePersonModel("id", "name", fakeClickIntent) + val fakeClickRunnable = mock(Runnable::class.java) + val fakePerson = fakePersonModel("id", "name", fakeClickRunnable) val fakeModel = PeopleHubModel(listOf(fakePerson)) val fakeModelDataSource = FakeDataSource(fakeModel) - val fakeSettingDataSource = FakeDataSource(true) val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl( mockActivityStarter, - fakeModelDataSource, - fakeSettingDataSource + fakeModelDataSource ) val fakeListener = FakeDataListener<PeopleHubViewModelFactory>() val mockClickView = mock(View::class.java) @@ -126,35 +124,7 @@ class PeopleHubViewControllerTest : SysuiTestCase() { people[0].onClick() - verify(mockActivityStarter).startPendingIntentDismissingKeyguard( - same(fakeClickIntent), - any(), - same(mockClickView) - ) - } - - @Test - fun testViewModelDataSource_notVisibleIfSettingDisabled() { - val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0) - val fakePerson = fakePersonModel("id", "name", fakeClickIntent) - val fakeModel = PeopleHubModel(listOf(fakePerson)) - val fakeModelDataSource = FakeDataSource(fakeModel) - val fakeSettingDataSource = FakeDataSource(false) - val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl( - mockActivityStarter, - fakeModelDataSource, - fakeSettingDataSource - ) - val fakeListener = FakeDataListener<PeopleHubViewModelFactory>() - val mockClickView = mock(View::class.java) - - factoryDataSource.registerListener(fakeListener) - - val viewModel = (fakeListener.lastSeen as Maybe.Just).value - .createWithAssociatedClickView(mockClickView) - assertThat(viewModel.isVisible).isFalse() - val people = viewModel.people.toList() - assertThat(people.size).isEqualTo(0) + verify(fakeClickRunnable).run() } } @@ -178,10 +148,10 @@ private fun <T> castNull(): T = null as T private fun fakePersonModel( id: String, name: CharSequence, - clickIntent: PendingIntent, + clickRunnable: Runnable, userId: Int = 0 ): PersonModel = - PersonModel(id, name, mock(Drawable::class.java), clickIntent, userId) + PersonModel(id, name, mock(Drawable::class.java), clickRunnable, userId) private fun fakePersonViewModel(name: CharSequence): PersonViewModel = PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java index 138ea392f8ef..e1ab33a174ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java @@ -30,6 +30,7 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; @@ -53,8 +54,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.UserHandle; import android.provider.Settings; @@ -117,7 +117,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { @Mock private ShortcutInfo mShortcutInfo; @Mock - private Bitmap mImage; + private Drawable mIconDrawable; @Rule public MockitoRule mockito = MockitoJUnit.rule(); @@ -183,8 +183,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { when(mShortcutInfo.getShortLabel()).thenReturn("Convo name"); List<ShortcutInfo> shortcuts = Arrays.asList(mShortcutInfo); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcuts); - when(mIconFactory.getConversationBitmap(any(ShortcutInfo.class), anyString(), anyInt())) - .thenReturn(mImage); + when(mIconFactory.getConversationDrawable( + any(ShortcutInfo.class), anyString(), anyInt(), anyBoolean())) + .thenReturn(mIconDrawable); mNotificationChannel = new NotificationChannel( TEST_CHANNEL, TEST_CHANNEL_NAME, IMPORTANCE_LOW); @@ -197,7 +198,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { .build(); mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, notification, UserHandle.CURRENT, null, 0); - mEntry = new NotificationEntryBuilder().setSbn(mSbn).build(); + mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo).build(); PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, BubblesTestActivity.class), 0); @@ -206,7 +207,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase { .createIntentBubble(bubbleIntent, Icon.createWithResource(mContext, R.drawable.android)).build()) .build(); - mBubbleEntry = new NotificationEntryBuilder().setSbn(mBubbleSbn).build(); + mBubbleEntry = new NotificationEntryBuilder() + .setSbn(mBubbleSbn) + .setShortcutInfo(mShortcutInfo) + .build(); mConversationChannel = new NotificationChannel( TEST_CHANNEL + " : " + CONVERSATION_ID, TEST_CHANNEL_NAME, IMPORTANCE_LOW); @@ -233,7 +237,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, true); final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon); - assertEquals(mImage, ((BitmapDrawable) view.getDrawable()).getBitmap()); + assertEquals(mIconDrawable, view.getDrawable()); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index ac4080868653..5d0349dbbb60 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -77,6 +77,7 @@ import com.android.systemui.util.time.FakeSystemClock; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -89,6 +90,7 @@ import org.mockito.stubbing.Answer; * Functional tests for notification inflation from {@link NotificationEntryManager}. */ @SmallTest +@Ignore("Flaking") @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) public class NotificationEntryManagerInflationTest extends SysuiTestCase { @@ -281,7 +283,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { null, false, false, - false); + false, + null); mRankingMap = new NotificationListenerService.RankingMap(new Ranking[] {ranking}); TestableLooper.get(this).processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java index 69e4f2205c35..18ea774e56f0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java @@ -25,6 +25,7 @@ import android.app.Notification; import android.media.MediaMetadata; import android.media.session.MediaSession; import android.media.session.PlaybackState; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.View; @@ -66,6 +67,9 @@ public class NotificationMediaTemplateViewWrapperTest extends SysuiTestCase { allowTestableLooperAsMainThread(); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); + + // These tests are for regular media style notifications, not controls in quick settings + Settings.System.putInt(mContext.getContentResolver(), "qs_media_player", 0); } private void makeTestNotification(long duration, boolean allowSeeking) throws Exception { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index abfbcd99167b..c64dd093a4c2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.stack; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING; +import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP; +import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE; import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT; import static org.mockito.ArgumentMatchers.any; @@ -107,7 +109,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Test public void testInsertHeader() { // GIVEN a stack with HI and LO rows but no section headers - setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); + setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE); // WHEN we update the section headers mSectionsManager.updateSectionBoundaries(); @@ -119,11 +121,15 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Test public void testRemoveHeader() { // GIVEN a stack that originally had a header between the HI and LO sections - setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); + setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); // WHEN the last LO row is replaced with a HI row - setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HEADER, ChildType.HIPRI); + setStackState( + ChildType.ALERTING, + ChildType.ALERTING, + ChildType.GENTLE_HEADER, + ChildType.ALERTING); clearInvocations(mNssl); mSectionsManager.updateSectionBoundaries(); @@ -134,7 +140,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Test public void testDoNothingIfHeaderAlreadyRemoved() { // GIVEN a stack with only HI rows - setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI); + setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING); // WHEN we update the sections headers mSectionsManager.updateSectionBoundaries(); @@ -147,19 +153,19 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { public void testMoveHeaderForward() { // GIVEN a stack that originally had a header between the HI and LO sections setStackState( - ChildType.HIPRI, - ChildType.HIPRI, - ChildType.HIPRI, - ChildType.LOPRI); + ChildType.ALERTING, + ChildType.ALERTING, + ChildType.ALERTING, + ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); // WHEN the LO section moves forward setStackState( - ChildType.HIPRI, - ChildType.HIPRI, - ChildType.LOPRI, - ChildType.HEADER, - ChildType.LOPRI); + ChildType.ALERTING, + ChildType.ALERTING, + ChildType.GENTLE, + ChildType.GENTLE_HEADER, + ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); // THEN the LO section header is also moved forward @@ -170,19 +176,19 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { public void testMoveHeaderBackward() { // GIVEN a stack that originally had a header between the HI and LO sections setStackState( - ChildType.HIPRI, - ChildType.LOPRI, - ChildType.LOPRI, - ChildType.LOPRI); + ChildType.ALERTING, + ChildType.GENTLE, + ChildType.GENTLE, + ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); // WHEN the LO section moves backward setStackState( - ChildType.HIPRI, - ChildType.HEADER, - ChildType.HIPRI, - ChildType.HIPRI, - ChildType.LOPRI); + ChildType.ALERTING, + ChildType.GENTLE_HEADER, + ChildType.ALERTING, + ChildType.ALERTING, + ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); // THEN the LO section header is also moved backward (with appropriate index shifting) @@ -193,14 +199,14 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { public void testHeaderRemovedFromTransientParent() { // GIVEN a stack where the header is animating away setStackState( - ChildType.HIPRI, - ChildType.LOPRI, - ChildType.LOPRI, - ChildType.LOPRI); + ChildType.ALERTING, + ChildType.GENTLE, + ChildType.GENTLE, + ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); setStackState( - ChildType.HIPRI, - ChildType.HEADER); + ChildType.ALERTING, + ChildType.GENTLE_HEADER); mSectionsManager.updateSectionBoundaries(); clearInvocations(mNssl); @@ -209,8 +215,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { // WHEN the LO section reappears setStackState( - ChildType.HIPRI, - ChildType.LOPRI); + ChildType.ALERTING, + ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); // THEN the header is first removed from the transient parent before being added to the @@ -223,7 +229,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { public void testHeaderNotShownOnLockscreen() { // GIVEN a stack of HI and LO notifs on the lockscreen when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); - setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); + setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE); // WHEN we update the section headers mSectionsManager.updateSectionBoundaries(); @@ -236,7 +242,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { public void testHeaderShownWhenEnterLockscreen() { // GIVEN a stack of HI and LO notifs on the lockscreen when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); - setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); + setStackState(ChildType.ALERTING, ChildType.ALERTING, ChildType.ALERTING, ChildType.GENTLE); mSectionsManager.updateSectionBoundaries(); // WHEN we unlock @@ -250,37 +256,104 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Test public void testHeaderHiddenWhenEnterLockscreen() { // GIVEN a stack of HI and LO notifs on the shade - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED); - setStackState(ChildType.HIPRI, ChildType.HIPRI, ChildType.HIPRI, ChildType.LOPRI); - mSectionsManager.updateSectionBoundaries(); + setStackState(ChildType.ALERTING, ChildType.GENTLE_HEADER, ChildType.GENTLE); // WHEN we go back to the keyguard when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); mSectionsManager.updateSectionBoundaries(); // Then the section header is removed - verify(mNssl).removeView(eq(mSectionsManager.getGentleHeaderView())); + verify(mNssl).removeView(mSectionsManager.getGentleHeaderView()); + } + + @Test + public void testPeopleFiltering_addHeadersFromShowingOnlyGentle() { + enablePeopleFiltering(); + + setStackState( + ChildType.GENTLE_HEADER, + ChildType.PERSON, + ChildType.ALERTING, + ChildType.GENTLE); + mSectionsManager.updateSectionBoundaries(); + + verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 2); + verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1); + verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0); + } + + @Test + public void testPeopleFiltering_addAllHeaders() { + enablePeopleFiltering(); + + setStackState( + ChildType.PERSON, + ChildType.ALERTING, + ChildType.GENTLE); + mSectionsManager.updateSectionBoundaries(); + + verify(mNssl).addView(mSectionsManager.getGentleHeaderView(), 2); + verify(mNssl).addView(mSectionsManager.getAlertingHeaderView(), 1); + verify(mNssl).addView(mSectionsManager.getPeopleHeaderView(), 0); } - private enum ChildType { HEADER, HIPRI, LOPRI } + @Test + public void testPeopleFiltering_moveAllHeaders() { + enablePeopleFiltering(); + + setStackState( + ChildType.PEOPLE_HEADER, + ChildType.ALERTING_HEADER, + ChildType.GENTLE_HEADER, + ChildType.PERSON, + ChildType.ALERTING, + ChildType.GENTLE); + mSectionsManager.updateSectionBoundaries(); + + verify(mNssl).changeViewPosition(mSectionsManager.getGentleHeaderView(), 4); + verify(mNssl).changeViewPosition(mSectionsManager.getAlertingHeaderView(), 2); + verify(mNssl).changeViewPosition(mSectionsManager.getPeopleHeaderView(), 0); + } + + private void enablePeopleFiltering() { + when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true); + when(mSectionsFeatureManager.getNumberOfBuckets()).thenReturn(4); + } + + private enum ChildType { + PEOPLE_HEADER, ALERTING_HEADER, GENTLE_HEADER, HEADS_UP, PERSON, ALERTING, GENTLE, OTHER + } private void setStackState(ChildType... children) { when(mNssl.getChildCount()).thenReturn(children.length); for (int i = 0; i < children.length; i++) { View child; switch (children[i]) { - case HEADER: + case PEOPLE_HEADER: + child = mSectionsManager.getPeopleHeaderView(); + break; + case ALERTING_HEADER: + child = mSectionsManager.getAlertingHeaderView(); + break; + case GENTLE_HEADER: child = mSectionsManager.getGentleHeaderView(); break; - case HIPRI: - case LOPRI: - ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class, - RETURNS_DEEP_STUBS); - when(notifRow.getVisibility()).thenReturn(View.VISIBLE); - when(notifRow.getEntry().getBucket()).thenReturn( - children[i] == ChildType.HIPRI ? BUCKET_ALERTING : BUCKET_SILENT); - when(notifRow.getParent()).thenReturn(mNssl); - child = notifRow; + case HEADS_UP: + child = mockNotification(BUCKET_HEADS_UP); + break; + case PERSON: + child = mockNotification(BUCKET_PEOPLE); + break; + case ALERTING: + child = mockNotification(BUCKET_ALERTING); + break; + case GENTLE: + child = mockNotification(BUCKET_SILENT); + break; + case OTHER: + child = mock(View.class); + when(child.getVisibility()).thenReturn(View.VISIBLE); + when(child.getParent()).thenReturn(mNssl); break; default: throw new RuntimeException("Unknown ChildType: " + children[i]); @@ -289,4 +362,13 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { when(mNssl.indexOfChild(child)).thenReturn(i); } } + + private View mockNotification(int bucket) { + ExpandableNotificationRow notifRow = mock(ExpandableNotificationRow.class, + RETURNS_DEEP_STUBS); + when(notifRow.getVisibility()).thenReturn(View.VISIBLE); + when(notifRow.getEntry().getBucket()).thenReturn(bucket); + when(notifRow.getParent()).thenReturn(mNssl); + return notifRow; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java index 3d59d6162c0c..dbb451277535 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static junit.framework.Assert.assertFalse; @@ -205,7 +206,8 @@ public class LightsOutNotifControllerTest extends SysuiTestCase { // WHEN all active notifications are removed when(mEntryManager.hasActiveNotifications()).thenReturn(false); assertFalse(mLightsOutNotifController.shouldShowDot()); - mEntryListener.onEntryRemoved(mock(NotificationEntry.class), null, false); + mEntryListener.onEntryRemoved( + mock(NotificationEntry.class), null, false, REASON_CANCEL_ALL); // THEN we shouldn't see the dot view assertIsShowingDot(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index 8f645b6bd3c8..9aa0fdd2a6f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -70,6 +70,7 @@ import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -255,6 +256,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { Optional.of(mRecents), () -> mock(StatusBar.class), mock(ShadeController.class), + mock(NotificationRemoteInputManager.class), mHandler); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java index e171a2894d2c..f6a099da3282 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; import static org.junit.Assert.assertFalse; @@ -254,7 +255,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupManager.onEntryAdded(summaryEntry); mGroupManager.onEntryAdded(childEntry); - mNotificationEntryListener.onEntryRemoved(childEntry, null, false); + mNotificationEntryListener.onEntryRemoved( + childEntry, null, false, UNDEFINED_DISMISS_REASON); assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry)); } 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 e917c93597ee..c5b69694bdfa 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,8 +37,9 @@ import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.DragDownHelper; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.NotificationShadeWindowBlurController; +import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -81,6 +82,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { @Mock private NotificationPanelViewController mNotificationPanelViewController; @Mock private NotificationStackScrollLayout mNotificationStackScrollLayout; @Mock private NotificationShadeWindowBlurController mNotificationShadeWindowBlurController; + @Mock private SuperStatusBarViewFactory mStatusBarViewFactory; @Before public void setUp() { @@ -116,7 +118,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mDockManager, mNotificationShadeWindowBlurController, mView, - mNotificationPanelViewController); + mNotificationPanelViewController, + mStatusBarViewFactory); mController.setupExpandedStatusBar(); mController.setService(mStatusBar); mController.setDragDownHelper(mDragDownHelper); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index d81b8c2af246..0035b98c9a8d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -122,6 +122,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; @@ -247,6 +248,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private KeyguardDismissUtil mKeyguardDismissUtil; @Mock private ExtensionController mExtensionController; @Mock private UserInfoControllerImpl mUserInfoControllerImpl; + @Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy; private ShadeController mShadeController; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private InitController mInitController = new InitController(); @@ -272,7 +274,7 @@ public class StatusBarTest extends SysuiTestCase { mMetricsLogger = new FakeMetricsLogger(); NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener, mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController, - mExpansionStateLogger); + mExpansionStateLogger, new NotificationPanelLoggerFake()); notificationLogger.setVisibilityReporter(mock(Runnable.class)); when(mCommandQueue.asBinder()).thenReturn(new Binder()); @@ -400,6 +402,7 @@ public class StatusBarTest extends SysuiTestCase { mKeyguardDismissUtil, mExtensionController, mUserInfoControllerImpl, + mPhoneStatusBarPolicy, mDismissCallbackRegistry, mStatusBarTouchableRegionManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java index cd91f22bb753..57714722aea4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.policy; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -140,13 +139,16 @@ public class HotspotControllerImplTest extends SysuiTestCase { } @Test - public void testDefault_hotspotNotSupported() { - assertFalse(mController.isHotspotSupported()); + public void testHotspotSupported_default() { + assertTrue(mController.isHotspotSupported()); } @Test public void testHotspotSupported_rightConditions() { mTetheringCallbackCaptor.getValue().onTetheringSupported(true); + + assertTrue(mController.isHotspotSupported()); + mTetheringCallbackCaptor.getValue() .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps); @@ -154,13 +156,21 @@ public class HotspotControllerImplTest extends SysuiTestCase { } @Test - public void testHotspotSupported_callbackCalledOnChange() { + public void testHotspotSupported_callbackCalledOnChange_tetheringSupported() { + mController.addCallback(mCallback1); + mTetheringCallbackCaptor.getValue().onTetheringSupported(false); + + verify(mCallback1).onHotspotAvailabilityChanged(false); + } + + @Test + public void testHotspotSupported_callbackCalledOnChange_tetherableInterfaces() { + when(mTetheringInterfaceRegexps.getTetherableWifiRegexs()) + .thenReturn(Collections.emptyList()); mController.addCallback(mCallback1); - mTetheringCallbackCaptor.getValue().onTetheringSupported(true); mTetheringCallbackCaptor.getValue() .onTetherableInterfaceRegexpsChanged(mTetheringInterfaceRegexps); - verify(mCallback1).onHotspotAvailabilityChanged(true); + verify(mCallback1).onHotspotAvailabilityChanged(false); } - } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 32da4c9650fb..9c250c5e8e16 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -72,7 +72,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { testSsid); setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, false, true); verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel], - null); + testSsid); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java index 0c9130d08d6d..44184ee8eeed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -28,6 +29,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,7 +39,6 @@ import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.NetworkRequest; import android.os.Handler; -import android.os.Looper; import android.os.UserManager; import android.security.IKeyChainService; import android.test.suitebuilder.annotation.SmallTest; @@ -46,34 +47,30 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @SmallTest @RunWith(AndroidJUnit4.class) -public class SecurityControllerTest extends SysuiTestCase implements SecurityControllerCallback { +public class SecurityControllerTest extends SysuiTestCase { private final DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class); private final IKeyChainService.Stub mKeyChainService = mock(IKeyChainService.Stub.class); private final UserManager mUserManager = mock(UserManager.class); + private final BroadcastDispatcher mBroadcastDispatcher = mock(BroadcastDispatcher.class); + private final Handler mHandler = mock(Handler.class); private SecurityControllerImpl mSecurityController; - private CountDownLatch mStateChangedLatch; private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class); - - // implementing SecurityControllerCallback - @Override - public void onStateChanged() { - mStateChangedLatch.countDown(); - } + private FakeExecutor mBgExecutor; + private BroadcastReceiver mBroadcastReceiver; @Before public void setUp() throws Exception { @@ -86,6 +83,7 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon mContext.addMockService(comp, mKeyChainService); when(mUserManager.getUserInfo(anyInt())).thenReturn(new UserInfo()); + when(mUserManager.isUserUnlocked(any())).thenReturn(true); when(mKeyChainService.getUserCaAliases()) .thenReturn(new StringParceledListSlice(new ArrayList<String>())); @@ -94,18 +92,23 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon when(mKeyChainService.queryLocalInterface("android.security.IKeyChainService")) .thenReturn(mKeyChainService); - // Wait for callbacks from the onUserSwitched() function in the - // constructor of mSecurityController - mStateChangedLatch = new CountDownLatch(1); - // TODO: Migrate this test to TestableLooper and use a handler attached - // to that. - mSecurityController = new SecurityControllerImpl(mContext, - new Handler(Looper.getMainLooper()), mock(BroadcastDispatcher.class), this); - } + ArgumentCaptor<BroadcastReceiver> brCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + mBgExecutor = new FakeExecutor(new FakeSystemClock()); + mSecurityController = new SecurityControllerImpl( + mContext, + mHandler, + mBroadcastDispatcher, + mBgExecutor); + + verify(mBroadcastDispatcher).registerReceiverWithHandler( + brCaptor.capture(), + anyObject(), + anyObject(), + anyObject()); - @After - public void tearDown() { - mSecurityController.removeCallback(this); + mBroadcastReceiver = brCaptor.getValue(); } @Test @@ -125,8 +128,6 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon @Test public void testWorkAccount() throws Exception { - // Wait for the callbacks from setUp() - assertTrue(mStateChangedLatch.await(1, TimeUnit.SECONDS)); assertFalse(mSecurityController.hasCACertInCurrentUser()); final int PRIMARY_USER_ID = 0; @@ -139,53 +140,41 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon assertTrue(mSecurityController.hasWorkProfile()); assertFalse(mSecurityController.hasCACertInWorkProfile()); - mStateChangedLatch = new CountDownLatch(1); - when(mKeyChainService.getUserCaAliases()) .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias"))); - mSecurityController.new CACertLoader() - .execute(MANAGED_USER_ID); + refreshCACerts(MANAGED_USER_ID); + mBgExecutor.runAllReady(); - assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS)); assertTrue(mSecurityController.hasCACertInWorkProfile()); } @Test public void testCaCertLoader() throws Exception { - // Wait for the callbacks from setUp() - assertTrue(mStateChangedLatch.await(1, TimeUnit.SECONDS)); assertFalse(mSecurityController.hasCACertInCurrentUser()); // With a CA cert - mStateChangedLatch = new CountDownLatch(1); - when(mKeyChainService.getUserCaAliases()) .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias"))); - mSecurityController.new CACertLoader() - .execute(0); + refreshCACerts(0); + mBgExecutor.runAllReady(); - assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS)); assertTrue(mSecurityController.hasCACertInCurrentUser()); // Exception - mStateChangedLatch = new CountDownLatch(1); - when(mKeyChainService.getUserCaAliases()) .thenThrow(new AssertionError("Test AssertionError")) .thenReturn(new StringParceledListSlice(new ArrayList<String>())); - mSecurityController.new CACertLoader() - .execute(0); + refreshCACerts(0); + mBgExecutor.runAllReady(); - assertFalse(mStateChangedLatch.await(1, TimeUnit.SECONDS)); assertTrue(mSecurityController.hasCACertInCurrentUser()); - mSecurityController.new CACertLoader() - .execute(0); + refreshCACerts(0); + mBgExecutor.runAllReady(); - assertTrue(mStateChangedLatch.await(1, TimeUnit.SECONDS)); assertFalse(mSecurityController.hasCACertInCurrentUser()); } @@ -196,4 +185,13 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon && request.networkCapabilities.getCapabilities().length == 0 ), any(NetworkCallback.class)); } + + /** + * refresh CA certs by sending a user unlocked broadcast for the desired user + */ + private void refreshCACerts(int userId) { + Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + mBroadcastReceiver.onReceive(mContext, intent); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java index c761a44170c3..e4e0dc9ec39c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java @@ -22,7 +22,6 @@ import static junit.framework.Assert.assertTrue; import android.app.RemoteInput; import android.os.Handler; -import android.os.Looper; import android.provider.DeviceConfig; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -32,8 +31,8 @@ import android.testing.TestableResources; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.DeviceConfigProxyFake; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,14 +41,13 @@ import org.junit.runner.RunWith; @TestableLooper.RunWithLooper @SmallTest public class SmartReplyConstantsTest extends SysuiTestCase { - - private static final int CONTENT_OBSERVER_TIMEOUT_SECONDS = 10; - private SmartReplyConstants mConstants; + private DeviceConfigProxyFake mDeviceConfig; + private TestableLooper mTestableLooper; @Before public void setUp() { - resetAllDeviceConfigFlags(); + mDeviceConfig = new DeviceConfigProxyFake(); TestableResources resources = mContext.getOrCreateTestableResources(); resources.addOverride(R.bool.config_smart_replies_in_notifications_enabled, true); resources.addOverride( @@ -62,12 +60,12 @@ public class SmartReplyConstantsTest extends SysuiTestCase { 2); resources.addOverride( R.integer.config_smart_replies_in_notifications_max_num_actions, -1); - mConstants = new SmartReplyConstants(Handler.createAsync(Looper.myLooper()), mContext); - } - - @After - public void tearDown() { - resetAllDeviceConfigFlags(); + mTestableLooper = TestableLooper.get(this); + mConstants = new SmartReplyConstants( + new Handler(mTestableLooper.getLooper()), + mContext, + mDeviceConfig + ); } @Test @@ -78,25 +76,21 @@ public class SmartReplyConstantsTest extends SysuiTestCase { @Test public void testIsEnabledWithInvalidConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_ENABLED, "invalid config"); - triggerConstantsOnChange(); assertTrue(mConstants.isEnabled()); } @Test public void testIsEnabledWithValidConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_ENABLED, "false"); - triggerConstantsOnChange(); assertFalse(mConstants.isEnabled()); } @Test public void testRequiresTargetingPConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P, "false"); - triggerConstantsOnChange(); assertEquals(false, mConstants.requiresTargetingP()); overrideSetting(SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P, null); - triggerConstantsOnChange(); assertEquals(true, mConstants.requiresTargetingP()); } @@ -110,20 +104,17 @@ public class SmartReplyConstantsTest extends SysuiTestCase { public void testGetMaxSqueezeRemeasureAttemptsWithInvalidConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS, "invalid config"); - triggerConstantsOnChange(); assertEquals(7, mConstants.getMaxSqueezeRemeasureAttempts()); } @Test public void testGetMaxSqueezeRemeasureAttemptsWithValidConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS, "5"); - triggerConstantsOnChange(); assertEquals(5, mConstants.getMaxSqueezeRemeasureAttempts()); } @Test public void testGetEffectiveEditChoicesBeforeSendingWithNoConfig() { - triggerConstantsOnChange(); assertFalse( mConstants.getEffectiveEditChoicesBeforeSending( RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO)); @@ -138,7 +129,6 @@ public class SmartReplyConstantsTest extends SysuiTestCase { @Test public void testGetEffectiveEditChoicesBeforeSendingWithEnabledConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_EDIT_CHOICES_BEFORE_SENDING, "true"); - triggerConstantsOnChange(); assertTrue( mConstants.getEffectiveEditChoicesBeforeSending( RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO)); @@ -153,7 +143,6 @@ public class SmartReplyConstantsTest extends SysuiTestCase { @Test public void testGetEffectiveEditChoicesBeforeSendingWithDisabledConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_EDIT_CHOICES_BEFORE_SENDING, "false"); - triggerConstantsOnChange(); assertFalse( mConstants.getEffectiveEditChoicesBeforeSending( RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO)); @@ -174,14 +163,12 @@ public class SmartReplyConstantsTest extends SysuiTestCase { @Test public void testShowInHeadsUpEnabled() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP, "true"); - triggerConstantsOnChange(); assertTrue(mConstants.getShowInHeadsUp()); } @Test public void testShowInHeadsUpDisabled() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP, "false"); - triggerConstantsOnChange(); assertFalse(mConstants.getShowInHeadsUp()); } @@ -194,7 +181,6 @@ public class SmartReplyConstantsTest extends SysuiTestCase { @Test public void testGetMinNumSystemGeneratedRepliesWithValidConfig() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_MIN_NUM_SYSTEM_GENERATED_REPLIES, "5"); - triggerConstantsOnChange(); assertEquals(5, mConstants.getMinNumSystemGeneratedReplies()); } @@ -207,7 +193,6 @@ public class SmartReplyConstantsTest extends SysuiTestCase { @Test public void testMaxNumActionsSet() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_MAX_NUM_ACTIONS, "10"); - triggerConstantsOnChange(); assertEquals(10, mConstants.getMaxNumActions()); } @@ -219,38 +204,12 @@ public class SmartReplyConstantsTest extends SysuiTestCase { @Test public void testOnClickInitDelaySet() { overrideSetting(SystemUiDeviceConfigFlags.SSIN_ONCLICK_INIT_DELAY, "50"); - triggerConstantsOnChange(); assertEquals(50, mConstants.getOnClickInitDelay()); } private void overrideSetting(String propertyName, String value) { - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, + mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, propertyName, value, false /* makeDefault */); - } - - private void triggerConstantsOnChange() { - mConstants.onDeviceConfigPropertiesChanged(DeviceConfig.NAMESPACE_SYSTEMUI); - } - - private void resetAllDeviceConfigFlags() { - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_ENABLED, null, false /* makeDefault */); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P, null, false /* makeDefault */); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_MAX_SQUEEZE_REMEASURE_ATTEMPTS, null, - false /* makeDefault */); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_EDIT_CHOICES_BEFORE_SENDING, null, - false /* makeDefault */); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP, null, false /* makeDefault */); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_MIN_NUM_SYSTEM_GENERATED_REPLIES, null, - false /* makeDefault */); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_MAX_NUM_ACTIONS, null, false /* makeDefault */); - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.SSIN_ONCLICK_INIT_DELAY, null, false /* makeDefault */); + mTestableLooper.processAllMessages(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java index d58f2c9c1791..bc3a5b193c8a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java @@ -105,6 +105,33 @@ public class ToastUITest extends SysuiTestCase { assertThat(windowParams.packageName).isEqualTo(mContext.getPackageName()); assertThat(windowParams.getTitle()).isEqualTo("Toast"); assertThat(windowParams.token).isEqualTo(WINDOW_TOKEN_1); + assertThat(windowParams.privateFlags + & WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isEqualTo(0); + } + + @Test + public void testShowToast_forAndroidPackage_addsAllUserFlag() throws Exception { + mToastUI.showToast("android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null); + + verify(mWindowManager).addView(any(), mParamsCaptor.capture()); + ViewGroup.LayoutParams params = mParamsCaptor.getValue(); + assertThat(params).isInstanceOf(WindowManager.LayoutParams.class); + WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params; + assertThat(windowParams.privateFlags + & WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isNotEqualTo(0); + } + + @Test + public void testShowToast_forSystemUiPackage_addsAllUserFlag() throws Exception { + mToastUI.showToast("com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + null); + + verify(mWindowManager).addView(any(), mParamsCaptor.capture()); + ViewGroup.LayoutParams params = mParamsCaptor.getValue(); + assertThat(params).isInstanceOf(WindowManager.LayoutParams.class); + WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params; + assertThat(windowParams.privateFlags + & WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isNotEqualTo(0); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java index 54cb0b83fc8f..31d884c38f58 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java @@ -20,11 +20,9 @@ import android.content.res.Resources; public class FakeProximitySensor extends ProximitySensor { private boolean mAvailable; - private boolean mPaused; public FakeProximitySensor(Resources resources, AsyncSensorManager sensorManager) { super(resources, sensorManager); - mAvailable = true; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java index 80aa6f6c49bc..8cc83dd99b53 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java @@ -29,6 +29,7 @@ import android.content.IntentFilter; import android.media.AudioManager; import android.media.session.MediaSession; import android.os.Handler; +import android.os.Process; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; @@ -116,13 +117,13 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { @Test public void testOnRemoteVolumeChanged_newStream_noNullPointer() { - MediaSession.Token token = new MediaSession.Token(null); + MediaSession.Token token = new MediaSession.Token(Process.myUid(), null); mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(token, 0); } @Test public void testOnRemoteRemove_newStream_noNullPointer() { - MediaSession.Token token = new MediaSession.Token(null); + MediaSession.Token token = new MediaSession.Token(Process.myUid(), null); mVolumeController.mMediaSessionsCallbacksW.onRemoteRemoved(token); } diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 3111ab701191..0c372351292c 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -95,11 +95,7 @@ java_defaults { // TODO (b/148190005): change to module-libs-api-stubs-current once it is ready. sdk_version: "core_platform", privileged: true, - // Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies - // explicitly. jni_libs: [ - "liblog", - "libnativehelper_compat_libc++", "libtetherutilsjni", ], resource_dirs: [ diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp index 94ef11cc127a..96a4d2007753 100644 --- a/packages/Tethering/apex/Android.bp +++ b/packages/Tethering/apex/Android.bp @@ -16,6 +16,7 @@ apex { name: "com.android.tethering", + updatable: true, java_libs: ["framework-tethering"], apps: ["Tethering"], manifest: "manifest.json", diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ar/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ar/strings.xml new file mode 100644 index 000000000000..307bf70731c3 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ar/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"حواف منحنية"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-bn/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-bn/strings.xml new file mode 100644 index 000000000000..565f75e6daad --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-bn/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"ওয়াটারফল কাট-আউট"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-bs/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-bs/strings.xml index c9cff0893590..594999f1b2e4 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-bs/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-bs/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Urez vodopada"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Izrezani vodopad"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-eu/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-eu/strings.xml new file mode 100644 index 000000000000..93ef2c8e2109 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-eu/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Ur-jauzi moduko mozketa"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-fr-rCA/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000000..7232c337ba13 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-fr-rCA/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Encoche en cascade"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-gu/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-gu/strings.xml new file mode 100644 index 000000000000..03672fe85a35 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-gu/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"વૉટરફૉલ કટઆઉટ"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-hi/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-hi/strings.xml new file mode 100644 index 000000000000..319d81a49d18 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-hi/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"वॉटरफ़ॉल कटआउट"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-it/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-it/strings.xml index dde9914ea044..3ea14c5ba292 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-it/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-it/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Ritaglio a cascata"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Curvatura Waterfall"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-iw/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-iw/strings.xml index f71a8796827b..5dbce7e82ef3 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-iw/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-iw/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"מגרעת מפל"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"שוליים מעוגלים"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ja/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ja/strings.xml index 354ce5926640..4db014997ea7 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ja/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ja/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"ウォーターフォールのカットアウト"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"エッジ スクリーン"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-kk/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-kk/strings.xml new file mode 100644 index 000000000000..bb0dfe98759c --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-kk/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Сарқырама ойығы"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-km/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-km/strings.xml index 8d2f887d5ed7..b73ccbb16533 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-km/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-km/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"អេក្រង់គ្មានគែម"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"គែមកោង"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ky/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ky/strings.xml new file mode 100644 index 000000000000..18e20831ee20 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ky/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Шаркыратманы кесүү"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-mk/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-mk/strings.xml index f39584ba933e..a330a35fea58 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-mk/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-mk/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Исечок во вид на водопад"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Прекин за Waterfall"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ml/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ml/strings.xml new file mode 100644 index 000000000000..112562dadb86 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ml/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"വെള്ളച്ചാട്ട കട്ടൗട്ട്"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt-rBR/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt-rBR/strings.xml index f80fcaddf764..3ead3c29f371 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt-rBR/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt-rBR/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Recorte de cascata"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Design cachoeira"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt/strings.xml index f80fcaddf764..3ead3c29f371 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-pt/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Recorte de cascata"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Design cachoeira"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ta/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ta/strings.xml new file mode 100644 index 000000000000..85d32c353b65 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-ta/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"வாட்டர்ஃபால் கட்அவுட்"</string> +</resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-th/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-th/strings.xml index 6c39a7fb35d5..e9b5e1fd40a1 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-th/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-th/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"คัตเอาท์ Waterfall"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"ขอบจอโค้ง"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-vi/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-vi/strings.xml index 2fff02778f7c..a063e8f45a4a 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-vi/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-vi/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Vết cắt trên thác nước"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"Vết cắt thác nước"</string> </resources> diff --git a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-zh-rTW/strings.xml b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-zh-rTW/strings.xml index 109b61cab681..56144e5d9fa3 100644 --- a/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-zh-rTW/strings.xml +++ b/packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-zh-rTW/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"瀑布裁剪圖片"</string> + <string name="display_cutout_emulation_overlay" msgid="3523556473422419323">"瀑布螢幕凹口"</string> </resources> diff --git a/packages/overlays/IconShapeFlowerOverlay/Android.mk b/packages/overlays/IconShapeFlowerOverlay/Android.mk new file mode 100644 index 000000000000..d410bb72b723 --- /dev/null +++ b/packages/overlays/IconShapeFlowerOverlay/Android.mk @@ -0,0 +1,29 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_RRO_THEME := IconShapeFlower + +LOCAL_PRODUCT_MODULE := true + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := IconShapeFlowerOverlay +LOCAL_SDK_VERSION := current + +include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/IconShapeFlowerOverlay/AndroidManifest.xml b/packages/overlays/IconShapeFlowerOverlay/AndroidManifest.xml new file mode 100644 index 000000000000..9d20c6b6f82c --- /dev/null +++ b/packages/overlays/IconShapeFlowerOverlay/AndroidManifest.xml @@ -0,0 +1,26 @@ +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.theme.icon.flower" + android:versionCode="1" + android:versionName="1.0"> + <overlay + android:targetPackage="android" + android:category="android.theme.customization.adaptive_icon_shape" + android:priority="1"/> + + <application android:label="@string/icon_shape_flower_overlay" android:hasCode="false"/> +</manifest> diff --git a/packages/overlays/IconShapeFlowerOverlay/res/values/config.xml b/packages/overlays/IconShapeFlowerOverlay/res/values/config.xml new file mode 100644 index 000000000000..73f4f2175a4b --- /dev/null +++ b/packages/overlays/IconShapeFlowerOverlay/res/values/config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. --> + <string name="config_icon_mask" translatable="false">"M50,0 C60.6,0 69.9,5.3 75.6,13.5 78.5,17.8 82.3,21.5 86.6,24.5 94.7,30.1 100,39.4 100,50 100,60.6 94.7,69.9 86.5,75.6 82.2,78.5 78.5,82.3 75.5,86.6 69.9,94.7 60.6,100 50,100 39.4,100 30.1,94.7 24.4,86.5 21.5,82.2 17.7,78.5 13.4,75.5 5.3,69.9 0,60.6 0,50 0,39.4 5.3,30.1 13.5,24.4 17.8,21.5 21.5,17.7 24.5,13.4 30.1,5.3 39.4,0 50,0 Z"</string> + <!-- Flag indicating whether round icons should be parsed from the application manifest. --> + <bool name="config_useRoundIcon">false</bool> + <!-- Corner radius of system dialogs --> + <dimen name="config_dialogCornerRadius">8dp</dimen> + <!-- Corner radius for bottom sheet system dialogs --> + <dimen name="config_bottomDialogCornerRadius">16dp</dimen> + +</resources> diff --git a/packages/overlays/IconShapeFlowerOverlay/res/values/strings.xml b/packages/overlays/IconShapeFlowerOverlay/res/values/strings.xml new file mode 100644 index 000000000000..47c1479e5a40 --- /dev/null +++ b/packages/overlays/IconShapeFlowerOverlay/res/values/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Flower icon overlay --> + <string name="icon_shape_flower_overlay" translatable="false">Flower</string> + +</resources> diff --git a/packages/overlays/IconShapeHexagonOverlay/Android.mk b/packages/overlays/IconShapeHexagonOverlay/Android.mk new file mode 100644 index 000000000000..16ef3995dedd --- /dev/null +++ b/packages/overlays/IconShapeHexagonOverlay/Android.mk @@ -0,0 +1,29 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_RRO_THEME := IconShapeHexagon + +LOCAL_PRODUCT_MODULE := true + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := IconShapeHexagonOverlay +LOCAL_SDK_VERSION := current + +include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/IconShapeHexagonOverlay/AndroidManifest.xml b/packages/overlays/IconShapeHexagonOverlay/AndroidManifest.xml new file mode 100644 index 000000000000..bf408fd62569 --- /dev/null +++ b/packages/overlays/IconShapeHexagonOverlay/AndroidManifest.xml @@ -0,0 +1,27 @@ +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.theme.icon.hexagon" + android:versionCode="1" + android:versionName="1.0"> + <overlay + android:targetPackage="android" + android:category="android.theme.customization.adaptive_icon_shape" + android:priority="1"/> + + <application android:label="@string/icon_shape_hexagon_overlay" android:hasCode="false"/> +</manifest> diff --git a/packages/overlays/IconShapeHexagonOverlay/res/values/config.xml b/packages/overlays/IconShapeHexagonOverlay/res/values/config.xml new file mode 100644 index 000000000000..f7cb5951b4f1 --- /dev/null +++ b/packages/overlays/IconShapeHexagonOverlay/res/values/config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. --> + <string name="config_icon_mask" translatable="false">"M12,0 88,0 100,50 88,100 12,100 0,50 12,0 Z"</string> + <!-- Flag indicating whether round icons should be parsed from the application manifest. --> + <bool name="config_useRoundIcon">false</bool> + <!-- Corner radius of system dialogs --> + <dimen name="config_dialogCornerRadius">0dp</dimen> + <!-- Corner radius for bottom sheet system dialogs --> + <dimen name="config_bottomDialogCornerRadius">0dp</dimen> + +</resources> diff --git a/packages/overlays/IconShapeHexagonOverlay/res/values/strings.xml b/packages/overlays/IconShapeHexagonOverlay/res/values/strings.xml new file mode 100644 index 000000000000..e00dc9d938ec --- /dev/null +++ b/packages/overlays/IconShapeHexagonOverlay/res/values/strings.xml @@ -0,0 +1,20 @@ +<!-- + ~ 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. + --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Hexagon icon overlay --> + <string name="icon_shape_hexagon_overlay" translatable="false">Hexagon</string> + +</resources> diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index c5a5d34ff30a..34d2b73ac2db 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -252,9 +252,6 @@ message SystemMessage { // Package: android NOTE_ID_WIFI_SIM_REQUIRED = 60; - // Inform the user a foreground service while-in-use permission is restricted. - NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION = 61; - // Display the Android Debug Protocol status // Package: android NOTE_ADB_WIFI_ACTIVE = 62; diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto index 789019ce8b75..2006fb3d7bf1 100644 --- a/proto/src/task_snapshot.proto +++ b/proto/src/task_snapshot.proto @@ -32,7 +32,12 @@ int32 system_ui_visibility = 8; bool is_translucent = 9; string top_activity_component = 10; - float scale = 11; + // deprecated because original width and height are stored now instead of the scale. + float legacy_scale = 11 [deprecated=true]; int64 id = 12; int32 rotation = 13; + // The task width when the snapshot was taken + int32 task_width = 14; + // The task height when the snapshot was taken + int32 task_height = 15; } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index a8a27916f56a..ad21075809ec 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -641,8 +641,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final SuspendDialogInfo dialogInfo = mPackageManagerInternal.getSuspendedDialogInfo(providerPackage, suspendingPackage, providerUserId); - // TODO(b/148035643): Send the original widget intent or ACTION_MAIN as an - // IntentSender to SuspendedAppActivity. + // onUnsuspend is null because we don't want to start any activity on + // unsuspending from a suspended widget. onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent( providerPackage, suspendingPackage, dialogInfo, null, null, providerUserId); @@ -794,6 +794,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku proto.write(WidgetProto.PROVIDER_PACKAGE, widget.provider.id.componentName.getPackageName()); proto.write(WidgetProto.PROVIDER_CLASS, widget.provider.id.componentName.getClassName()); if (widget.options != null) { + proto.write(WidgetProto.RESTORE_COMPLETED, + widget.options.getBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED)); proto.write(WidgetProto.MIN_WIDTH, widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 0)); proto.write(WidgetProto.MIN_HEIGHT, @@ -2509,7 +2511,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku out.endTag(null, "h"); } - private static void serializeAppWidget(XmlSerializer out, Widget widget) throws IOException { + private static void serializeAppWidget(XmlSerializer out, Widget widget, + boolean saveRestoreCompleted) throws IOException { out.startTag(null, "g"); out.attribute(null, "id", Integer.toHexString(widget.appWidgetId)); out.attribute(null, "rid", Integer.toHexString(widget.restoredId)); @@ -2528,10 +2531,50 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku out.attribute(null, "max_height", Integer.toHexString((maxHeight > 0) ? maxHeight : 0)); out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt( AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))); + if (saveRestoreCompleted) { + boolean restoreCompleted = widget.options.getBoolean( + AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED); + out.attribute(null, "restore_completed", Boolean.toString(restoreCompleted)); + } } out.endTag(null, "g"); } + private static Bundle parseWidgetIdOptions(XmlPullParser parser) { + Bundle options = new Bundle(); + String restoreCompleted = parser.getAttributeValue(null, "restore_completed"); + if (restoreCompleted != null) { + options.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED, + Boolean.valueOf(restoreCompleted)); + } + String minWidthString = parser.getAttributeValue(null, "min_width"); + if (minWidthString != null) { + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, + Integer.parseInt(minWidthString, 16)); + } + String minHeightString = parser.getAttributeValue(null, "min_height"); + if (minHeightString != null) { + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, + Integer.parseInt(minHeightString, 16)); + } + String maxWidthString = parser.getAttributeValue(null, "max_width"); + if (maxWidthString != null) { + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, + Integer.parseInt(maxWidthString, 16)); + } + String maxHeightString = parser.getAttributeValue(null, "max_height"); + if (maxHeightString != null) { + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, + Integer.parseInt(maxHeightString, 16)); + } + String categoryString = parser.getAttributeValue(null, "host_category"); + if (categoryString != null) { + options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, + Integer.parseInt(categoryString, 16)); + } + return options; + } + @Override public List<String> getWidgetParticipants(int userId) { return mBackupRestoreController.getWidgetParticipants(userId); @@ -3064,7 +3107,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (widget.host.getUserId() != userId) { continue; } - serializeAppWidget(out, widget); + serializeAppWidget(out, widget, true); } Iterator<Pair<Integer, String>> it = mPackagesWithBindWidgetPermission.iterator(); @@ -3203,34 +3246,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku String restoredIdString = parser.getAttributeValue(null, "rid"); widget.restoredId = (restoredIdString == null) ? 0 : Integer.parseInt(restoredIdString, 16); - - Bundle options = new Bundle(); - String minWidthString = parser.getAttributeValue(null, "min_width"); - if (minWidthString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, - Integer.parseInt(minWidthString, 16)); - } - String minHeightString = parser.getAttributeValue(null, "min_height"); - if (minHeightString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, - Integer.parseInt(minHeightString, 16)); - } - String maxWidthString = parser.getAttributeValue(null, "max_width"); - if (maxWidthString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, - Integer.parseInt(maxWidthString, 16)); - } - String maxHeightString = parser.getAttributeValue(null, "max_height"); - if (maxHeightString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, - Integer.parseInt(maxHeightString, 16)); - } - String categoryString = parser.getAttributeValue(null, "host_category"); - if (categoryString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, - Integer.parseInt(categoryString, 16)); - } - widget.options = options; + widget.options = parseWidgetIdOptions(parser); final int hostTag = Integer.parseInt(parser.getAttributeValue( null, "h"), 16); @@ -4382,7 +4398,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (widget.host.isInPackageForUser(backedupPackage, userId) || (provider != null && provider.isInPackageForUser(backedupPackage, userId))) { - serializeAppWidget(out, widget); + serializeAppWidget(out, widget, false); } } @@ -4815,36 +4831,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku || widget.provider.getUserId() == userId); } - private Bundle parseWidgetIdOptions(XmlPullParser parser) { - Bundle options = new Bundle(); - String minWidthString = parser.getAttributeValue(null, "min_width"); - if (minWidthString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, - Integer.parseInt(minWidthString, 16)); - } - String minHeightString = parser.getAttributeValue(null, "min_height"); - if (minHeightString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, - Integer.parseInt(minHeightString, 16)); - } - String maxWidthString = parser.getAttributeValue(null, "max_width"); - if (maxWidthString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, - Integer.parseInt(maxWidthString, 16)); - } - String maxHeightString = parser.getAttributeValue(null, "max_height"); - if (maxHeightString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, - Integer.parseInt(maxHeightString, 16)); - } - String categoryString = parser.getAttributeValue(null, "host_category"); - if (categoryString != null) { - options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, - Integer.parseInt(categoryString, 16)); - } - return options; - } - private int countPendingUpdates(ArrayList<RestoreUpdateRecord> updates) { int pending = 0; final int N = updates.size(); diff --git a/services/art-profile b/services/art-profile index 1f53ebd4a930..ae3f6d125042 100644 --- a/services/art-profile +++ b/services/art-profile @@ -42281,7 +42281,6 @@ Lcom/android/server/incident/RequestQueue$1; Lcom/android/server/incident/RequestQueue$Rec; Lcom/android/server/incident/RequestQueue; Lcom/android/server/incremental/IncrementalManagerService; -Lcom/android/server/incremental/IncrementalManagerShellCommand; Lcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$1$TLhe3_2yHs5UB69Y7lf2s7OxJCo; Lcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$_fKw-VUP0pSfcMMlgRqoT4OPhxw; Lcom/android/server/infra/-$$Lambda$AbstractMasterSystemService$su3lJpEVIbL-C7doP4eboTpqjxU; diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java index 6daa1064c89e..941244994dab 100644 --- a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java +++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java @@ -24,8 +24,10 @@ import android.content.ComponentName; import android.os.Bundle; import android.os.RemoteException; import android.util.Log; +import android.util.Slog; import android.view.autofill.AutofillId; import android.view.inputmethod.InlineSuggestionsRequest; +import android.view.inputmethod.InlineSuggestionsResponse; import com.android.internal.annotations.GuardedBy; import com.android.internal.view.IInlineSuggestionsRequestCallback; @@ -33,6 +35,8 @@ import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.server.inputmethod.InputMethodManagerInternal; +import java.util.Collections; +import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -40,9 +44,16 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** - * Maintains an inline suggestion autofill session. + * Maintains an autofill inline suggestion session that communicates with the IME. * - * <p> This class is thread safe. + * <p> + * The same session may be reused for multiple input fields involved in the same autofill + * {@link Session}. Therefore, one {@link InlineSuggestionsRequest} and one + * {@link IInlineSuggestionsResponseCallback} may be used to generate and callback with inline + * suggestions for different input fields. + * + * <p> + * This class is thread safe. */ final class InlineSuggestionSession { @@ -61,6 +72,9 @@ final class InlineSuggestionSession { @Nullable private CompletableFuture<ImeResponse> mPendingImeResponse; + @GuardedBy("mLock") + private boolean mIsLastResponseNonEmpty = false; + InlineSuggestionSession(InputMethodManagerInternal inputMethodManagerInternal, int userId, ComponentName componentName) { mInputMethodManagerInternal = inputMethodManagerInternal; @@ -69,26 +83,28 @@ final class InlineSuggestionSession { mLock = new Object(); } - public void createRequest(@NonNull AutofillId currentViewId) { + public void onCreateInlineSuggestionsRequest(@NonNull AutofillId autofillId) { + if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequest called for " + autofillId); + synchronized (mLock) { cancelCurrentRequest(); mPendingImeResponse = new CompletableFuture<>(); // TODO(b/146454892): pipe the uiExtras from the ExtServices. mInputMethodManagerInternal.onCreateInlineSuggestionsRequest( mUserId, - new InlineSuggestionsRequestInfo(mComponentName, currentViewId, new Bundle()), + new InlineSuggestionsRequestInfo(mComponentName, autofillId, new Bundle()), new InlineSuggestionsRequestCallbackImpl(mPendingImeResponse)); } } - @Nullable - public ImeResponse waitAndGetImeResponse() { - CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse(); - if (pendingImeResponse == null || pendingImeResponse.isCancelled()) { - return null; + public Optional<InlineSuggestionsRequest> waitAndGetInlineSuggestionsRequest() { + final CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse(); + if (pendingImeResponse == null) { + return Optional.empty(); } try { - return pendingImeResponse.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS); + return Optional.ofNullable(pendingImeResponse.get(INLINE_REQUEST_TIMEOUT_MS, + TimeUnit.MILLISECONDS)).map(ImeResponse::getRequest); } catch (TimeoutException e) { Log.w(TAG, "Exception getting inline suggestions request in time: " + e); } catch (CancellationException e) { @@ -96,13 +112,59 @@ final class InlineSuggestionSession { } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } - return null; + return Optional.empty(); + } + + public boolean hideInlineSuggestionsUi(@NonNull AutofillId autofillId) { + if (sDebug) Log.d(TAG, "Called hideInlineSuggestionsUi for " + autofillId); + synchronized (mLock) { + if (mIsLastResponseNonEmpty) { + if (sDebug) Log.d(TAG, "Send empty suggestion to IME"); + return onInlineSuggestionsResponseLocked(autofillId, + new InlineSuggestionsResponse(Collections.EMPTY_LIST)); + } + return false; + } + } + + public boolean onInlineSuggestionsResponse(@NonNull AutofillId autofillId, + @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) { + synchronized (mLock) { + return onInlineSuggestionsResponseLocked(autofillId, inlineSuggestionsResponse); + } + } + + private boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId, + @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) { + final CompletableFuture<ImeResponse> completedImsResponse = getPendingImeResponse(); + if (completedImsResponse == null || !completedImsResponse.isDone()) { + return false; + } + // There is no need to wait on the CompletableFuture since it should have been completed + // when {@link #waitAndGetInlineSuggestionsRequest()} was called. + ImeResponse imeResponse = completedImsResponse.getNow(null); + if (imeResponse == null) { + return false; + } + try { + imeResponse.mCallback.onInlineSuggestionsResponse(autofillId, + inlineSuggestionsResponse); + mIsLastResponseNonEmpty = !inlineSuggestionsResponse.getInlineSuggestions().isEmpty(); + if (sDebug) { + Log.d(TAG, "Autofill sends inline response to IME: " + + inlineSuggestionsResponse.getInlineSuggestions().size()); + } + return true; + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException sending InlineSuggestionsResponse to IME"); + return false; + } } private void cancelCurrentRequest() { CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse(); - if (pendingImeResponse != null) { - pendingImeResponse.cancel(true); + if (pendingImeResponse != null && !pendingImeResponse.isDone()) { + pendingImeResponse.complete(null); } } @@ -125,22 +187,18 @@ final class InlineSuggestionSession { @Override public void onInlineSuggestionsUnsupported() throws RemoteException { - if (sDebug) { - Log.d(TAG, "onInlineSuggestionsUnsupported() called."); - } - mResponse.cancel(true); + if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called."); + mResponse.complete(null); } @Override public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, - IInlineSuggestionsResponseCallback callback) throws RemoteException { - if (sDebug) { - Log.d(TAG, "onInlineSuggestionsRequest() received: " + request); - } + IInlineSuggestionsResponseCallback callback) { + if (sDebug) Log.d(TAG, "onInlineSuggestionsRequest() received: " + request); if (request != null && callback != null) { mResponse.complete(new ImeResponse(request, callback)); } else { - mResponse.cancel(true); + mResponse.complete(null); } } } @@ -148,12 +206,12 @@ final class InlineSuggestionSession { /** * A data class wrapping IME responses for the inline suggestion request. */ - public static class ImeResponse { + private static class ImeResponse { @NonNull - private final InlineSuggestionsRequest mRequest; + final InlineSuggestionsRequest mRequest; @NonNull - private final IInlineSuggestionsResponseCallback mCallback; + final IInlineSuggestionsResponseCallback mCallback; ImeResponse(@NonNull InlineSuggestionsRequest request, @NonNull IInlineSuggestionsResponseCallback callback) { @@ -161,12 +219,8 @@ final class InlineSuggestionSession { mCallback = callback; } - public InlineSuggestionsRequest getRequest() { + InlineSuggestionsRequest getRequest() { return mRequest; } - - public IInlineSuggestionsResponseCallback getCallback() { - return mCallback; - } } } diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index 1eb769216e63..dcc91811905a 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -37,6 +37,7 @@ import android.os.ICancellationSignal; import android.os.RemoteException; import android.os.SystemClock; import android.service.autofill.Dataset; +import android.service.autofill.InlinePresentation; import android.service.autofill.augmented.AugmentedAutofillService; import android.service.autofill.augmented.IAugmentedAutofillService; import android.service.autofill.augmented.IFillCallback; @@ -47,20 +48,21 @@ import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.view.autofill.IAutoFillManagerClient; import android.view.inputmethod.InlineSuggestionsRequest; +import android.view.inputmethod.InlineSuggestionsResponse; import com.android.internal.infra.AbstractRemoteService; import com.android.internal.infra.AndroidFuture; import com.android.internal.infra.ServiceConnector; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.IResultReceiver; -import com.android.internal.util.ArrayUtils; -import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.server.autofill.ui.InlineSuggestionFactory; +import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; final class RemoteAugmentedAutofillService extends ServiceConnector.Impl<IAugmentedAutofillService> { @@ -145,7 +147,7 @@ final class RemoteAugmentedAutofillService int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue, @Nullable InlineSuggestionsRequest inlineSuggestionsRequest, - @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback, + @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback, @NonNull Runnable onErrorCallback, @NonNull RemoteInlineSuggestionRenderService remoteRenderService) { long requestTime = SystemClock.elapsedRealtime(); @@ -164,12 +166,13 @@ final class RemoteAugmentedAutofillService focusedId, focusedValue, requestTime, inlineSuggestionsRequest, new IFillCallback.Stub() { @Override - public void onSuccess(@Nullable Dataset[] inlineSuggestionsData) { + public void onSuccess(@Nullable List<Dataset> inlineSuggestionsData, + @Nullable List<InlinePresentation> inlineActions) { mCallbacks.resetLastResponse(); maybeRequestShowInlineSuggestions(sessionId, inlineSuggestionsRequest, inlineSuggestionsData, - focusedId, inlineSuggestionsCallback, client, - onErrorCallback, remoteRenderService); + inlineActions, focusedId, inlineSuggestionsCallback, + client, onErrorCallback, remoteRenderService); requestAutofill.complete(null); } @@ -232,36 +235,39 @@ final class RemoteAugmentedAutofillService } private void maybeRequestShowInlineSuggestions(int sessionId, - @Nullable InlineSuggestionsRequest request, @Nullable Dataset[] inlineSuggestionsData, - @NonNull AutofillId focusedId, - @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback, + @Nullable InlineSuggestionsRequest request, + @Nullable List<Dataset> inlineSuggestionsData, + @Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId focusedId, + @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback, @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback, @NonNull RemoteInlineSuggestionRenderService remoteRenderService) { - if (ArrayUtils.isEmpty(inlineSuggestionsData) || inlineSuggestionsCallback == null - || request == null) { + if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty() + || inlineSuggestionsCallback == null || request == null) { return; } mCallbacks.setLastResponse(sessionId); - try { - inlineSuggestionsCallback.onInlineSuggestionsResponse( - InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse( - request, inlineSuggestionsData, focusedId, mContext, - dataset -> { - mCallbacks.logAugmentedAutofillSelected(sessionId, - dataset.getId()); - try { - client.autofill(sessionId, dataset.getFieldIds(), - dataset.getFieldValues()); - } catch (RemoteException e) { - Slog.w(TAG, "Encounter exception autofilling the values"); - } - }, onErrorCallback, remoteRenderService)); - } catch (RemoteException e) { - Slog.w(TAG, "Exception sending inline suggestions response back to IME."); - } + final InlineSuggestionsResponse inlineSuggestionsResponse = + InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse( + request, inlineSuggestionsData, inlineActions, focusedId, mContext, + dataset -> { + mCallbacks.logAugmentedAutofillSelected(sessionId, + dataset.getId()); + try { + client.autofill(sessionId, dataset.getFieldIds(), + dataset.getFieldValues()); + } catch (RemoteException e) { + Slog.w(TAG, "Encounter exception autofilling the values"); + } + }, onErrorCallback, remoteRenderService); - mCallbacks.logAugmentedAutofillShown(sessionId); + if (inlineSuggestionsResponse == null) { + Slog.w(TAG, "InlineSuggestionFactory created null response"); + return; + } + if (inlineSuggestionsCallback.apply(inlineSuggestionsResponse)) { + mCallbacks.logAugmentedAutofillShown(sessionId); + } } @Override diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 317ce4cb5fee..6fb65cae2482 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -100,7 +100,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.ArrayUtils; -import com.android.internal.view.IInlineSuggestionsResponseCallback; import com.android.server.autofill.ui.AutoFillUI; import com.android.server.autofill.ui.InlineSuggestionFactory; import com.android.server.autofill.ui.PendingUi; @@ -113,6 +112,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; /** @@ -403,11 +403,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final ArrayList<FillContext> contexts = mergePreviousSessionLocked(/* forSave= */ false); - final InlineSuggestionSession.ImeResponse imeResponse = - mInlineSuggestionSession.waitAndGetImeResponse(); - + final Optional<InlineSuggestionsRequest> inlineSuggestionsRequest = + mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest(); request = new FillRequest(requestId, contexts, mClientState, flags, - imeResponse != null ? imeResponse.getRequest() : null); + inlineSuggestionsRequest.orElse(null)); } if (mActivityToken != null) { @@ -605,7 +604,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private void maybeRequestInlineSuggestionsRequestThenFillLocked(@NonNull ViewState viewState, int newState, int flags) { if (isInlineSuggestionsEnabled()) { - mInlineSuggestionSession.createRequest(mCurrentViewId); + mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId); } requestNewFillResponseLocked(viewState, newState, flags); @@ -1158,18 +1157,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } catch (RemoteException e) { Slog.e(TAG, "Error requesting to hide fill UI", e); } - try { - final InlineSuggestionSession.ImeResponse imeResponse = - mInlineSuggestionSession.waitAndGetImeResponse(); - if (imeResponse == null) { - Log.w(TAG, "Session input method callback is not set yet"); - return; - } - imeResponse.getCallback().onInlineSuggestionsResponse( - new InlineSuggestionsResponse(Collections.EMPTY_LIST)); - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException hiding inline suggestions"); - } } } @@ -2501,6 +2488,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (sVerbose) Slog.v(TAG, "Exiting view " + id); mUi.hideFillUi(this); hideAugmentedAutofillLocked(viewState); + mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId); mCurrentViewId = null; } break; @@ -2668,32 +2656,27 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response, @Nullable String filterText) { - final List<Dataset> datasets = response.getDatasets(); - - final InlineSuggestionSession.ImeResponse imeResponse = - mInlineSuggestionSession.waitAndGetImeResponse(); - if (imeResponse == null) { - Log.w(TAG, "Session input method callback is not set yet"); + final Optional<InlineSuggestionsRequest> inlineSuggestionsRequest = + mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest(); + if (!inlineSuggestionsRequest.isPresent()) { + Log.w(TAG, "InlineSuggestionsRequest unavailable"); return false; } - - final InlineSuggestionsRequest request = imeResponse.getRequest(); InlineSuggestionsResponse inlineSuggestionsResponse = - InlineSuggestionFactory.createInlineSuggestionsResponse(request, + InlineSuggestionFactory.createInlineSuggestionsResponse( + inlineSuggestionsRequest.get(), response, filterText, response.getInlineActions(), mCurrentViewId, mContext, this, () -> { synchronized (mLock) { requestHideFillUi(mCurrentViewId); } }, mService.getRemoteInlineSuggestionRenderServiceLocked()); - try { - imeResponse.getCallback().onInlineSuggestionsResponse(inlineSuggestionsResponse); - } catch (RemoteException e) { - Log.w(TAG, "onFillReady() remote error calling onInlineSuggestionsResponse()"); + if (inlineSuggestionsResponse == null) { + Slog.w(TAG, "InlineSuggestionFactory created null response"); return false; } - - return true; + return mInlineSuggestionSession.onInlineSuggestionsResponse(mCurrentViewId, + inlineSuggestionsResponse); } boolean isDestroyed() { @@ -2976,16 +2959,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // doesn't want autofill if (mForAugmentedAutofillOnly || !isInlineSuggestionsEnabled()) { if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill"); - mInlineSuggestionSession.createRequest(mCurrentViewId); - } - InlineSuggestionSession.ImeResponse imeResponse = - mInlineSuggestionSession.waitAndGetImeResponse(); - final InlineSuggestionsRequest inlineSuggestionsRequest = - imeResponse != null ? imeResponse.getRequest() : null; - final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback = - imeResponse != null ? imeResponse.getCallback() : null; + mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId); + } + + Optional<InlineSuggestionsRequest> inlineSuggestionsRequest = + mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest(); remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId, - currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback, () -> { + currentValue, inlineSuggestionsRequest.orElse(null), + response -> mInlineSuggestionSession.onInlineSuggestionsResponse( + mCurrentViewId, response), + () -> { synchronized (mLock) { cancelAugmentedAutofillLocked(); } diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java index fef49d44bed0..9bf369089e50 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java @@ -70,6 +70,7 @@ public final class InlineSuggestionFactory { * Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by the * autofill service, potentially filtering the datasets. */ + @Nullable public static InlineSuggestionsResponse createInlineSuggestionsResponse( @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response, @Nullable String filterText, @Nullable List<InlinePresentation> inlineActions, @@ -92,23 +93,21 @@ public final class InlineSuggestionFactory { }; } - final List<Dataset> datasetList = response.getDatasets(); - final Dataset[] datasets = datasetList == null - ? null - : datasetList.toArray(new Dataset[]{}); final InlinePresentation inlineAuthentication = response.getAuthentication() == null ? null : response.getInlinePresentation(); return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request, - datasets, filterText, inlineAuthentication, inlineActions, autofillId, context, - onErrorCallback, onClickFactory, remoteRenderService); + response.getDatasets(), filterText, inlineAuthentication, inlineActions, autofillId, + context, onErrorCallback, onClickFactory, remoteRenderService); } /** * Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by augmented * autofill service. */ + @Nullable public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse( - @NonNull InlineSuggestionsRequest request, @NonNull Dataset[] datasets, + @NonNull InlineSuggestionsRequest request, @NonNull List<Dataset> datasets, + @Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId autofillId, @NonNull Context context, @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback, @NonNull Runnable onErrorCallback, @@ -116,14 +115,15 @@ public final class InlineSuggestionFactory { if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called"); return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request, datasets, /* filterText= */ null, /* inlineAuthentication= */ null, - /* inlineActions= */ null, autofillId, context, onErrorCallback, + inlineActions, autofillId, context, onErrorCallback, (dataset, datasetIndex) -> inlineSuggestionUiCallback.autofill(dataset), remoteRenderService); } + @Nullable private static InlineSuggestionsResponse createInlineSuggestionsResponseInternal( boolean isAugmented, @NonNull InlineSuggestionsRequest request, - @Nullable Dataset[] datasets, @Nullable String filterText, + @Nullable List<Dataset> datasets, @Nullable String filterText, @Nullable InlinePresentation inlineAuthentication, @Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId autofillId, @NonNull Context context, @NonNull Runnable onErrorCallback, @@ -145,18 +145,18 @@ public final class InlineSuggestionFactory { return null; } - for (int datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) { - final Dataset dataset = datasets[datasetIndex]; + for (int datasetIndex = 0; datasetIndex < datasets.size(); datasetIndex++) { + final Dataset dataset = datasets.get(datasetIndex); final int fieldIndex = dataset.getFieldIds().indexOf(autofillId); if (fieldIndex < 0) { Slog.w(TAG, "AutofillId=" + autofillId + " not found in dataset"); - return null; + continue; } final InlinePresentation inlinePresentation = dataset.getFieldInlinePresentation( fieldIndex); if (inlinePresentation == null) { Slog.w(TAG, "InlinePresentation not found in dataset"); - return null; + continue; } if (!includeDataset(dataset, fieldIndex, filterText)) { continue; @@ -169,7 +169,8 @@ public final class InlineSuggestionFactory { inlineSuggestions.add(inlineSuggestion); } - if (inlineActions != null) { + // We should only add inline actions if there is at least one suggestion. + if (!inlineSuggestions.isEmpty() && inlineActions != null) { for (InlinePresentation inlinePresentation : inlineActions) { final InlineSuggestion inlineAction = createInlineAction(isAugmented, context, mergedInlinePresentation(request, 0, inlinePresentation), @@ -219,12 +220,12 @@ public final class InlineSuggestionFactory { @Nullable RemoteInlineSuggestionRenderService remoteRenderService, @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken, int displayId) { - // TODO(b/146453195): fill in the autofill hint properly. final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo( inlinePresentation.getInlinePresentationSpec(), isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM - : InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""}, - InlineSuggestionInfo.TYPE_ACTION); + : InlineSuggestionInfo.SOURCE_AUTOFILL, + inlinePresentation.getAutofillHints(), + InlineSuggestionInfo.TYPE_ACTION, inlinePresentation.isPinned()); final Runnable onClickAction = () -> { Toast.makeText(context, "icon clicked", Toast.LENGTH_SHORT).show(); }; @@ -240,12 +241,12 @@ public final class InlineSuggestionFactory { @NonNull RemoteInlineSuggestionRenderService remoteRenderService, @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken, int displayId) { - // TODO(b/146453195): fill in the autofill hint properly. final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo( inlinePresentation.getInlinePresentationSpec(), isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM - : InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""}, - InlineSuggestionInfo.TYPE_SUGGESTION); + : InlineSuggestionInfo.SOURCE_AUTOFILL, + inlinePresentation.getAutofillHints(), + InlineSuggestionInfo.TYPE_SUGGESTION, inlinePresentation.isPinned()); final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo, createInlineContentProvider(inlinePresentation, @@ -262,7 +263,8 @@ public final class InlineSuggestionFactory { @Nullable IBinder hostInputToken, int displayId) { final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo( inlinePresentation.getInlinePresentationSpec(), - InlineSuggestionInfo.SOURCE_AUTOFILL, null, InlineSuggestionInfo.TYPE_SUGGESTION); + InlineSuggestionInfo.SOURCE_AUTOFILL, inlinePresentation.getAutofillHints(), + InlineSuggestionInfo.TYPE_SUGGESTION, inlinePresentation.isPinned()); return new InlineSuggestion(inlineSuggestionInfo, createInlineContentProvider(inlinePresentation, diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 434a97ee0bc5..6ccdf245b271 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -369,10 +369,13 @@ public class CompanionDeviceManagerService extends SystemService implements Bind boolean bypassMacPermission = getContext().getPackageManager().checkPermission( android.Manifest.permission.COMPANION_APPROVE_WIFI_CONNECTIONS, packageName) == PackageManager.PERMISSION_GRANTED; + if (bypassMacPermission) { + return true; + } return CollectionUtils.any( readAllAssociations(userId, packageName), - a -> bypassMacPermission || Objects.equals(a.deviceAddress, macAddress)); + a -> Objects.equals(a.deviceAddress, macAddress)); } private void checkCanCallNotificationApi(String callingPackage) throws RemoteException { diff --git a/services/core/Android.bp b/services/core/Android.bp index 4da60b8e4ffd..84ce34b4676f 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -99,6 +99,7 @@ java_library_static { "android.hardware.vibrator-java", "app-compat-annotations", "framework-tethering-stubs", + "ike-stubs", ], required: [ @@ -127,6 +128,7 @@ java_library_static { "dnsresolver_aidl_interface-V2-java", "netd_event_listener_interface-java", "ike-stubs", + "overlayable_policy_aidl-java", ], plugins: [ diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 1b1e06a9a92f..485127a79c27 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -845,18 +845,11 @@ public abstract class PackageManagerInternal { "android.content.pm.extra.ENABLE_ROLLBACK_TOKEN"; /** - * Extra field name for the installFlags of a request to enable rollback + * Extra field name for the session id of a request to enable rollback * for a package. */ - public static final String EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS = - "android.content.pm.extra.ENABLE_ROLLBACK_INSTALL_FLAGS"; - - /** - * Extra field name for the user id an install is associated with when - * enabling rollback. - */ - public static final String EXTRA_ENABLE_ROLLBACK_USER = - "android.content.pm.extra.ENABLE_ROLLBACK_USER"; + public static final String EXTRA_ENABLE_ROLLBACK_SESSION_ID = + "android.content.pm.extra.ENABLE_ROLLBACK_SESSION_ID"; /** * Used as the {@code enableRollbackCode} argument for diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 3441a5f19508..7840b1957031 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -1670,6 +1670,7 @@ class AlarmManagerService extends SystemService { Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND + | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); intent.putExtra("time-zone", zone.getID()); getContext().sendBroadcastAsUser(intent, UserHandle.ALL); diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 7ec2a34604ca..dbf179abad4b 100644 --- a/services/core/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java @@ -687,7 +687,7 @@ public abstract class IntentResolver<F, R extends Object> { } private final void remove_all_objects(ArrayMap<String, F[]> map, String name, - Object object) { + F object) { F[] array = map.get(name); if (array != null) { int LAST = array.length-1; @@ -695,7 +695,8 @@ public abstract class IntentResolver<F, R extends Object> { LAST--; } for (int idx=LAST; idx>=0; idx--) { - if (array[idx] == object) { + F arrayValue = array[idx]; + if (arrayValue != null && getIntentFilter(arrayValue) == getIntentFilter(object)) { final int remain = LAST - idx; if (remain > 0) { System.arraycopy(array, idx+1, array, idx, remain); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 95bfbd72dc56..57c6e5b876b1 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -4366,18 +4366,24 @@ class StorageManagerService extends IStorageManager.Stub final IVold vold = IVold.Stub.asInterface( ServiceManager.getServiceOrThrow("vold")); for (String pkg : packageList) { - final String obbDir = - String.format("/storage/emulated/%d/Android/obb", userId); - final String packageObbDir = String.format("%s/%s/", obbDir, pkg); + final String packageObbDir = + String.format("/storage/emulated/%d/Android/obb/%s/", userId, pkg); + final String packageDataDir = + String.format("/storage/emulated/%d/Android/data/%s/", + userId, pkg); - // Create package obb dir if it doesn't exist. + // Create package obb and data dir if it doesn't exist. File file = new File(packageObbDir); if (!file.exists()) { vold.setupAppDir(packageObbDir, mPmInternal.getPackage(pkg).getUid()); } + file = new File(packageDataDir); + if (!file.exists()) { + vold.setupAppDir(packageDataDir, mPmInternal.getPackage(pkg).getUid()); + } } } catch (ServiceManager.ServiceNotFoundException | RemoteException e) { - Slog.e(TAG, "Unable to create obb directories for " + processName, e); + Slog.e(TAG, "Unable to create obb and data directories for " + processName, e); } } } @@ -4497,42 +4503,42 @@ class StorageManagerService extends IStorageManager.Stub } public void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode) { - if (mIsFuseEnabled) { - // When using FUSE, we may need to kill the app if the op changes - switch(code) { - case OP_REQUEST_INSTALL_PACKAGES: - // Always kill regardless of op change, to remount apps /storage - killAppForOpChange(code, uid, packageName); - return; - case OP_MANAGE_EXTERNAL_STORAGE: - if (mode != MODE_ALLOWED) { - // Only kill if op is denied, to lose external_storage gid - // Killing when op is granted to pickup the gid automatically, results - // in a bad UX, especially since the gid only gives access to unreliable - // volumes, USB OTGs that are rarely mounted. The app will get the - // external_storage gid on next organic restart. + final long token = Binder.clearCallingIdentity(); + try { + if (mIsFuseEnabled) { + // When using FUSE, we may need to kill the app if the op changes + switch(code) { + case OP_REQUEST_INSTALL_PACKAGES: + // Always kill regardless of op change, to remount apps /storage killAppForOpChange(code, uid, packageName); - } - return; - case OP_LEGACY_STORAGE: - updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED); - return; + return; + case OP_MANAGE_EXTERNAL_STORAGE: + if (mode != MODE_ALLOWED) { + // Only kill if op is denied, to lose external_storage gid + // Killing when op is granted to pickup the gid automatically, + // results in a bad UX, especially since the gid only gives access + // to unreliable volumes, USB OTGs that are rarely mounted. The app + // will get the external_storage gid on next organic restart. + killAppForOpChange(code, uid, packageName); + } + return; + case OP_LEGACY_STORAGE: + updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED); + return; + } } - } - if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE - || code == OP_WRITE_EXTERNAL_STORAGE - || code == OP_REQUEST_INSTALL_PACKAGES)) { - final long token = Binder.clearCallingIdentity(); - try { + if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE + || code == OP_WRITE_EXTERNAL_STORAGE + || code == OP_REQUEST_INSTALL_PACKAGES)) { final UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); if (userManagerInternal.isUserInitialized(UserHandle.getUserId(uid))) { onExternalStoragePolicyChanged(uid, packageName); } - } finally { - Binder.restoreCallingIdentity(token); } + } finally { + Binder.restoreCallingIdentity(token); } } } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 6763c513ec93..f619d6927fdb 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -98,7 +98,8 @@ final class UiModeManagerService extends SystemService { private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; private int mNightMode = UiModeManager.MODE_NIGHT_NO; // we use the override auto mode - // for example: force night mode off in the night time while in auto mode + // for example: force night mode off in the night time + // while in auto mode private int mNightModeOverride = mNightMode; private final LocalTime DEFAULT_CUSTOM_NIGHT_START_TIME = LocalTime.of(22, 0); private final LocalTime DEFAULT_CUSTOM_NIGHT_END_TIME = LocalTime.of(6, 0); @@ -152,6 +153,7 @@ final class UiModeManagerService extends SystemService { private PowerManager.WakeLock mWakeLock; private final LocalService mLocalService = new LocalService(); + private PowerManagerInternal mLocalPowerManager; public UiModeManagerService(Context context) { super(context); @@ -160,6 +162,7 @@ final class UiModeManagerService extends SystemService { @VisibleForTesting protected UiModeManagerService(Context context, WindowManagerInternal wm, AlarmManager am, PowerManager pm, PowerManager.WakeLock wl, TwilightManager tm, + PowerManagerInternal localPowerManager, boolean setupWizardComplete) { super(context); mWindowManager = wm; @@ -168,6 +171,8 @@ final class UiModeManagerService extends SystemService { mSetupWizardComplete = setupWizardComplete; mAlarmManager = am; mPowerManager = pm; + mLocalPowerManager = localPowerManager; + initPowerSave(); } private static Intent buildHomeIntent(String category) { @@ -230,11 +235,11 @@ final class UiModeManagerService extends SystemService { @Override public void onTwilightStateChanged(@Nullable TwilightState state) { synchronized (mLock) { - if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + if (mNightMode == UiModeManager.MODE_NIGHT_AUTO && mSystemReady) { if (mCar) { updateLocked(0, 0); } else { - registerScreenOffEvent(); + registerScreenOffEventLocked(); } } } @@ -250,7 +255,7 @@ final class UiModeManagerService extends SystemService { public void onReceive(Context context, Intent intent) { synchronized (mLock) { // must unregister first before updating - unregisterScreenOffEvent(); + unregisterScreenOffEventLocked(); updateLocked(0, 0); } } @@ -326,8 +331,7 @@ final class UiModeManagerService extends SystemService { public void onStart() { final Context context = getContext(); - mPowerManager = - (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); mWindowManager = LocalServices.getService(WindowManagerInternal.class); mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); @@ -341,21 +345,11 @@ final class UiModeManagerService extends SystemService { IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); context.registerReceiver(mBatteryReceiver, batteryFilter); - PowerManagerInternal localPowerManager = + mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class); - mPowerSave = localPowerManager.getLowPowerState(ServiceType.NIGHT_MODE).batterySaverEnabled; - localPowerManager.registerLowPowerModeObserver(ServiceType.NIGHT_MODE, - state -> { - synchronized (mLock) { - if (mPowerSave == state.batterySaverEnabled) { - return; - } - mPowerSave = state.batterySaverEnabled; - if (mSystemReady) { - updateLocked(0, 0); - } - } - }); + initPowerSave(); + + mTwilightManager = getLocalService(TwilightManager.class); mConfiguration.setToDefaults(); @@ -396,7 +390,24 @@ final class UiModeManagerService extends SystemService { context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE), false, mDarkThemeObserver, 0); - updateSystemProperties(); + mHandler.post(() -> updateSystemProperties()); + } + + private void initPowerSave() { + mPowerSave = + mLocalPowerManager.getLowPowerState(ServiceType.NIGHT_MODE) + .batterySaverEnabled; + mLocalPowerManager.registerLowPowerModeObserver(ServiceType.NIGHT_MODE, state -> { + synchronized (mLock) { + if (mPowerSave == state.batterySaverEnabled) { + return; + } + mPowerSave = state.batterySaverEnabled; + if (mSystemReady) { + updateLocked(0, 0); + } + } + }); } @VisibleForTesting @@ -433,7 +444,7 @@ final class UiModeManagerService extends SystemService { if (shouldApplyAutomaticChangesImmediately()) { updateLocked(0, 0); } else { - registerScreenOffEvent(); + registerScreenOffEventLocked(); } scheduleNextCustomTimeListener(); } @@ -473,7 +484,8 @@ final class UiModeManagerService extends SystemService { return oldNightMode != mNightMode; } - private void registerScreenOffEvent() { + private void registerScreenOffEventLocked() { + if (mPowerSave) return; mWaitForScreenOff = true; final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); @@ -484,7 +496,7 @@ final class UiModeManagerService extends SystemService { mAlarmManager.cancel(mCustomTimeListener); } - private void unregisterScreenOffEvent() { + private void unregisterScreenOffEventLocked() { mWaitForScreenOff = false; try { getContext().unregisterReceiver(mOnScreenOffHandler); @@ -630,7 +642,7 @@ final class UiModeManagerService extends SystemService { synchronized (mLock) { if (mNightMode != mode) { if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) { - unregisterScreenOffEvent(); + unregisterScreenOffEventLocked(); cancelCustomAlarm(); } @@ -643,10 +655,10 @@ final class UiModeManagerService extends SystemService { // on screen off will update configuration instead if ((mNightMode != MODE_NIGHT_AUTO && mNightMode != MODE_NIGHT_CUSTOM) || shouldApplyAutomaticChangesImmediately()) { - unregisterScreenOffEvent(); + unregisterScreenOffEventLocked(); updateLocked(0, 0); } else { - registerScreenOffEvent(); + registerScreenOffEventLocked(); } } } @@ -695,7 +707,7 @@ final class UiModeManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) { - unregisterScreenOffEvent(); + unregisterScreenOffEventLocked(); mNightModeOverride = active ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO; } else if (mNightMode == UiModeManager.MODE_NIGHT_NO @@ -737,7 +749,7 @@ final class UiModeManagerService extends SystemService { persistNightMode(user); onCustomTimeUpdated(user); } catch (DateTimeException e) { - unregisterScreenOffEvent(); + unregisterScreenOffEventLocked(); } finally { Binder.restoreCallingIdentity(ident); } @@ -764,7 +776,7 @@ final class UiModeManagerService extends SystemService { mCustomAutoNightModeEndMilliseconds = newTime; onCustomTimeUpdated(user); } catch (DateTimeException e) { - unregisterScreenOffEvent(); + unregisterScreenOffEventLocked(); } finally { Binder.restoreCallingIdentity(ident); } @@ -775,10 +787,10 @@ final class UiModeManagerService extends SystemService { persistNightMode(user); if (mNightMode != MODE_NIGHT_CUSTOM) return; if (shouldApplyAutomaticChangesImmediately()) { - unregisterScreenOffEvent(); + unregisterScreenOffEventLocked(); updateLocked(0, 0); } else { - registerScreenOffEvent(); + registerScreenOffEventLocked(); } } @@ -788,6 +800,7 @@ final class UiModeManagerService extends SystemService { pw.print(" mDockState="); pw.print(mDockState); pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mNightModeOverride="); pw.print(mNightModeOverride); pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" ("); pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); pw.print(" mNightModeLocked="); pw.println(mNightModeLocked); @@ -802,6 +815,8 @@ final class UiModeManagerService extends SystemService { } pw.println(""); pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); + pw.print(" customStart="); pw.print(mCustomAutoNightModeStartMilliseconds); + pw.print(" customEnd"); pw.print(mCustomAutoNightModeEndMilliseconds); pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); @@ -824,7 +839,6 @@ final class UiModeManagerService extends SystemService { public void onBootPhase(int phase) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { synchronized (mLock) { - mTwilightManager = getLocalService(TwilightManager.class); mSystemReady = true; mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; registerVrStateListener(); @@ -1011,6 +1025,10 @@ final class UiModeManagerService extends SystemService { uiMode = Configuration.UI_MODE_TYPE_VR_HEADSET; } + if (mNightMode == MODE_NIGHT_YES || mNightMode == UiModeManager.MODE_NIGHT_NO) { + updateComputedNightModeLocked(mNightMode == MODE_NIGHT_YES); + } + if (mNightMode == MODE_NIGHT_AUTO) { boolean activateNightMode = mComputedNightMode; if (mTwilightManager != null) { @@ -1020,12 +1038,10 @@ final class UiModeManagerService extends SystemService { } updateComputedNightModeLocked(activateNightMode); - uiMode = getComputedUiModeConfiguration(uiMode); } else { if (mTwilightManager != null) { mTwilightManager.unregisterListener(mTwilightListener); } - uiMode |= mNightMode << 4; } if (mNightMode == MODE_NIGHT_CUSTOM) { @@ -1033,7 +1049,6 @@ final class UiModeManagerService extends SystemService { final boolean activate = computeCustomNightMode(); updateComputedNightModeLocked(activate); scheduleNextCustomTimeListener(); - uiMode = getComputedUiModeConfiguration(uiMode); } else { unregisterTimeChangeEvent(); } @@ -1042,6 +1057,8 @@ final class UiModeManagerService extends SystemService { if (mPowerSave && !mCarModeEnabled) { uiMode &= ~Configuration.UI_MODE_NIGHT_NO; uiMode |= Configuration.UI_MODE_NIGHT_YES; + } else { + uiMode = getComputedUiModeConfiguration(uiMode); } if (LOG) { @@ -1053,7 +1070,7 @@ final class UiModeManagerService extends SystemService { } mCurUiMode = uiMode; - if (!mHoldingConfiguration && !mWaitForScreenOff) { + if (!mHoldingConfiguration && (!mWaitForScreenOff || mPowerSave)) { mConfiguration.uiMode = uiMode; } } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 0f1a6520ed4f..dd9cc641f2dd 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -183,7 +183,8 @@ public class VibratorService extends IVibratorService.Stub static native boolean vibratorSupportsAmplitudeControl(); static native void vibratorSetAmplitude(int amplitude); static native int[] vibratorGetSupportedEffects(); - static native long vibratorPerformEffect(long effect, long strength, Vibration vibration); + static native long vibratorPerformEffect(long effect, long strength, Vibration vibration, + boolean withCallback); static native void vibratorPerformComposedEffect( VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration); static native boolean vibratorSupportsExternalControl(); @@ -1334,7 +1335,8 @@ public class VibratorService extends IVibratorService.Stub // Input devices don't support prebaked effect, so skip trying it with them. if (!usingInputDeviceVibrators) { long duration = vibratorPerformEffect(prebaked.getId(), - prebaked.getEffectStrength(), vib); + prebaked.getEffectStrength(), vib, + hasCapability(IVibrator.CAP_PERFORM_CALLBACK)); long timeout = duration; if (hasCapability(IVibrator.CAP_PERFORM_CALLBACK)) { timeout *= ASYNC_TIMEOUT_MULTIPLIER; diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index 7ccb28474604..7aaf9be1fdd2 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -144,6 +144,18 @@ public class AdbService extends IAdbManager.Stub { public File getAdbTempKeysFile() { return mDebuggingManager.getAdbTempKeysFile(); } + + @Override + public void startAdbdForTransport(byte transportType) { + FgThread.getHandler().sendMessage(obtainMessage( + AdbService::setAdbdEnabledForTransport, AdbService.this, true, transportType)); + } + + @Override + public void stopAdbdForTransport(byte transportType) { + FgThread.getHandler().sendMessage(obtainMessage( + AdbService::setAdbdEnabledForTransport, AdbService.this, false, transportType)); + } } private void initAdbState() { @@ -437,6 +449,19 @@ public class AdbService extends IAdbManager.Stub { } } + private void setAdbdEnabledForTransport(boolean enable, byte transportType) { + if (transportType == AdbTransportType.USB) { + mIsAdbUsbEnabled = enable; + } else if (transportType == AdbTransportType.WIFI) { + mIsAdbWifiEnabled = enable; + } + if (enable) { + startAdbd(); + } else { + stopAdbd(); + } + } + private void setAdbEnabled(boolean enable, byte transportType) { if (DEBUG) { Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 7f98c7f2ba85..cfc8b459b8a5 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST; @@ -23,6 +24,7 @@ import static android.os.Process.NFC_UID; import static android.os.Process.ROOT_UID; import static android.os.Process.SHELL_UID; import static android.os.Process.SYSTEM_UID; +import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOREGROUND_SERVICE; @@ -36,6 +38,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE_E import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -88,11 +91,13 @@ import android.util.EventLog; import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.webkit.WebViewZygote; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.procstats.ServiceState; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.notification.SystemNotificationChannels; @@ -177,6 +182,10 @@ public final class ActiveServices { /** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */ private ArrayList<ServiceRecord> mTmpCollectionResults = null; + /** Mapping from uid to their foreground service AppOpCallbacks (if they have one). */ + @GuardedBy("mAm") + private final SparseArray<AppOpCallback> mFgsAppOpCallbacks = new SparseArray<>(); + /** * For keeping ActiveForegroundApps retaining state while the screen is off. */ @@ -685,8 +694,8 @@ public final class ActiveServices { if (!r.mAllowWhileInUsePermissionInFgs) { r.mAllowWhileInUsePermissionInFgs = - shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingUid, - service, r, allowBackgroundActivityStarts); + shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid, + callingUid, service, r, allowBackgroundActivityStarts); } return cmp; @@ -1455,7 +1464,9 @@ public final class ActiveServices { null, true, false, ""); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER); + FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER, + r.mAllowWhileInUsePermissionInFgs); + registerAppOpCallbackLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, true); } r.postNotification(); @@ -1504,9 +1515,11 @@ public final class ActiveServices { mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); + unregisterAppOpCallbackLocked(r); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT); + FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, + r.mAllowWhileInUsePermissionInFgs); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); if (r.app != null) { mAm.updateLruProcessLocked(r.app, false, null); @@ -1527,6 +1540,207 @@ public final class ActiveServices { } } + /** Registers an AppOpCallback for monitoring special AppOps for this foreground service. */ + private void registerAppOpCallbackLocked(@NonNull ServiceRecord r) { + if (r.app == null) { + return; + } + final int uid = r.appInfo.uid; + AppOpCallback callback = mFgsAppOpCallbacks.get(uid); + if (callback == null) { + callback = new AppOpCallback(r.app, mAm.getAppOpsManager()); + mFgsAppOpCallbacks.put(uid, callback); + } + callback.registerLocked(); + } + + /** Unregisters a foreground service's AppOpCallback. */ + private void unregisterAppOpCallbackLocked(@NonNull ServiceRecord r) { + final int uid = r.appInfo.uid; + final AppOpCallback callback = mFgsAppOpCallbacks.get(uid); + if (callback != null) { + callback.unregisterLocked(); + if (callback.isObsoleteLocked()) { + mFgsAppOpCallbacks.remove(uid); + } + } + } + + /** + * For monitoring when {@link #LOGGED_AP_OPS} AppOps occur by an app while it is holding + * at least one foreground service and is not also in the TOP state. + * Once the uid no longer holds any foreground services, this callback becomes stale + * (marked by {@link #isObsoleteLocked()}) and must no longer be used. + * + * Methods that end in Locked should only be called while the mAm lock is held. + */ + private static final class AppOpCallback { + /** AppOps that should be logged if they occur during a foreground service. */ + private static final int[] LOGGED_AP_OPS = new int[] { + AppOpsManager.OP_COARSE_LOCATION, + AppOpsManager.OP_FINE_LOCATION, + AppOpsManager.OP_RECORD_AUDIO, + AppOpsManager.OP_CAMERA + }; + + private final ProcessRecord mProcessRecord; + + /** Count of acceptances per appop (for LOGGED_AP_OPS) during this fgs session. */ + @GuardedBy("mCounterLock") + private final SparseIntArray mAcceptedOps = new SparseIntArray(); + /** Count of rejections per appop (for LOGGED_AP_OPS) during this fgs session. */ + @GuardedBy("mCounterLock") + private final SparseIntArray mRejectedOps = new SparseIntArray(); + + /** Lock for the purposes of mAcceptedOps and mRejectedOps. */ + private final Object mCounterLock = new Object(); + + /** + * AppOp Mode (e.g. {@link AppOpsManager#MODE_ALLOWED} per op. + * This currently cannot change without the process being killed, so they are constants. + */ + private final SparseIntArray mAppOpModes = new SparseIntArray(); + + /** + * Number of foreground services currently associated with this AppOpCallback (i.e. + * currently held for this uid). + */ + @GuardedBy("mAm") + private int mNumFgs = 0; + + /** + * Indicates that this Object is stale and must not be used. + * Specifically, when mNumFgs decreases down to 0, the callbacks will be unregistered and + * this AppOpCallback is unusable. + */ + @GuardedBy("mAm") + private boolean mDestroyed = false; + + private final AppOpsManager mAppOpsManager; + + AppOpCallback(@NonNull ProcessRecord r, @NonNull AppOpsManager appOpsManager) { + mProcessRecord = r; + mAppOpsManager = appOpsManager; + for (int op : LOGGED_AP_OPS) { + int mode = appOpsManager.unsafeCheckOpRawNoThrow(op, r.uid, r.info.packageName); + mAppOpModes.put(op, mode); + } + } + + private final AppOpsManager.OnOpNotedListener mOpNotedCallback = + new AppOpsManager.OnOpNotedListener() { + @Override + public void onOpNoted(int op, int uid, String pkgName, int result) { + if (uid == mProcessRecord.uid && isNotTop()) { + incrementOpCount(op, result == AppOpsManager.MODE_ALLOWED); + } + } + }; + + private final AppOpsManager.OnOpActiveChangedInternalListener mOpActiveCallback = + new AppOpsManager.OnOpActiveChangedInternalListener() { + @Override + public void onOpActiveChanged(int op, int uid, String pkgName, boolean active) { + if (uid == mProcessRecord.uid && active && isNotTop()) { + incrementOpCount(op, true); + } + } + }; + + private boolean isNotTop() { + return mProcessRecord.getCurProcState() != ActivityManager.PROCESS_STATE_TOP; + } + + private void incrementOpCount(int op, boolean allowed) { + synchronized (mCounterLock) { + final SparseIntArray counter = allowed ? mAcceptedOps : mRejectedOps; + final int index = counter.indexOfKey(op); + if (index < 0) { + counter.put(op, 1); + } else { + counter.setValueAt(index, counter.valueAt(index) + 1); + } + } + } + + void registerLocked() { + if (isObsoleteLocked()) { + Slog.wtf(TAG, "Trying to register on a stale AppOpCallback."); + return; + } + mNumFgs++; + if (mNumFgs == 1) { + mAppOpsManager.startWatchingNoted(LOGGED_AP_OPS, mOpNotedCallback); + mAppOpsManager.startWatchingActive(LOGGED_AP_OPS, mOpActiveCallback); + } + } + + void unregisterLocked() { + mNumFgs--; + if (mNumFgs <= 0) { + mDestroyed = true; + logFinalValues(); + mAppOpsManager.stopWatchingNoted(mOpNotedCallback); + mAppOpsManager.stopWatchingActive(mOpActiveCallback); + } + } + + /** + * Indicates that all foreground services for this uid are now over and the callback is + * stale and must never be used again. + */ + boolean isObsoleteLocked() { + return mDestroyed; + } + + private void logFinalValues() { + synchronized (mCounterLock) { + for (int op : LOGGED_AP_OPS) { + final int acceptances = mAcceptedOps.get(op); + final int rejections = mRejectedOps.get(op); + if (acceptances > 0 || rejections > 0) { + FrameworkStatsLog.write( + FrameworkStatsLog.FOREGROUND_SERVICE_APP_OP_SESSION_ENDED, + mProcessRecord.uid, opToEnum(op), + modeToEnum(mAppOpModes.get(op)), + acceptances, rejections + ); + } + } + } + } + + /** Maps AppOp mode to atoms.proto enum. */ + private static int modeToEnum(int mode) { + switch (mode) { + case AppOpsManager.MODE_ALLOWED: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_ALLOWED; + case AppOpsManager.MODE_IGNORED: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_IGNORED; + case AppOpsManager.MODE_FOREGROUND: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_FOREGROUND; + default: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_MODE__MODE_UNKNOWN; + } + } + } + + /** Maps AppOp op value to atoms.proto enum. */ + private static int opToEnum(int op) { + switch (op) { + case AppOpsManager.OP_COARSE_LOCATION: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_COARSE_LOCATION; + case AppOpsManager.OP_FINE_LOCATION: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_FINE_LOCATION; + case AppOpsManager.OP_CAMERA: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_CAMERA; + case AppOpsManager.OP_RECORD_AUDIO: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_RECORD_AUDIO; + default: return FrameworkStatsLog + .FOREGROUND_SERVICE_APP_OP_SESSION_ENDED__APP_OP_NAME__OP_NONE; + } + } + private void cancelForegroundNotificationLocked(ServiceRecord r) { if (r.foregroundId != 0) { // First check to see if this app has any other active foreground services @@ -1865,9 +2079,9 @@ public final class ActiveServices { } if (!s.mAllowWhileInUsePermissionInFgs) { - final int callingUid = Binder.getCallingUid(); s.mAllowWhileInUsePermissionInFgs = - shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingUid, + shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, + Binder.getCallingPid(), Binder.getCallingUid(), service, s, false); } @@ -2724,8 +2938,10 @@ public final class ActiveServices { // Not running -- get it started, and enqueue this service record // to be executed when the app comes up. if (app == null && !permissionsReviewRequired) { + // TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service + // was initiated from a notification tap or not. if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, - hostingRecord, false, isolated, false)) == null) { + hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) { String msg = "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " @@ -3136,9 +3352,11 @@ public final class ActiveServices { mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null); + unregisterAppOpCallbackLocked(r); FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortInstanceName, - FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT); + FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT, + r.mAllowWhileInUsePermissionInFgs); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); } @@ -3286,8 +3504,11 @@ public final class ActiveServices { } } - // If unbound while waiting to start, remove the pending service - mPendingServices.remove(s); + // If unbound while waiting to start and there is no connection left in this service, + // remove the pending service + if (s.getConnections().isEmpty()) { + mPendingServices.remove(s); + } if ((c.flags&Context.BIND_AUTO_CREATE) != 0) { boolean hasAutoCreate = s.hasAutoCreateConnections(); @@ -4625,7 +4846,8 @@ public final class ActiveServices { * @return true if allow, false otherwise. */ private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage, - int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) { + int callingPid, int callingUid, Intent intent, ServiceRecord r, + boolean allowBackgroundActivityStarts) { // Is the background FGS start restriction turned on? if (!mAm.mConstants.mFlagBackgroundFgsStartRestrictionEnabled) { return true; @@ -4635,13 +4857,6 @@ public final class ActiveServices { return true; } - // Is the service in a whitelist? - final boolean hasAllowBackgroundActivityStartsToken = r.app != null - ? r.app.mAllowBackgroundActivityStartsTokens.contains(r) : false; - if (hasAllowBackgroundActivityStartsToken) { - return true; - } - boolean isCallerSystem = false; final int callingAppId = UserHandle.getAppId(callingUid); switch (callingAppId) { @@ -4660,6 +4875,24 @@ public final class ActiveServices { return true; } + if (r.app != null) { + ActiveInstrumentation instr = r.app.getActiveInstrumentation(); + if (instr != null && instr.mHasBackgroundActivityStartsPermission) { + return true; + } + } + + final boolean hasAllowBackgroundActivityStartsToken = r.app != null + ? !r.app.mAllowBackgroundActivityStartsTokens.isEmpty() : false; + if (hasAllowBackgroundActivityStartsToken) { + return true; + } + + if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid) + == PERMISSION_GRANTED) { + return true; + } + // Is the calling UID at PROCESS_STATE_TOP or above? final boolean isCallingUidTopApp = appIsTopLocked(callingUid); if (isCallingUidTopApp) { @@ -4687,35 +4920,7 @@ public final class ActiveServices { } // TODO: remove this toast after feature development is done - private void showWhileInUsePermissionInFgsBlockedNotificationLocked(String callingPackage, - String detailInfo) { - final Context context = mAm.mContext; - final String title = "Foreground Service While-in-use Permission Restricted"; - final String content = "App affected:" + callingPackage + ", please file a bug report"; - Notification.Builder n = - new Notification.Builder(context, - SystemNotificationChannels.ALERTS) - .setSmallIcon(R.drawable.stat_sys_vitals) - .setWhen(0) - .setColor(context.getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setTicker(title) - .setContentTitle(title) - .setContentText(content) - .setStyle(new Notification.BigTextStyle().bigText(detailInfo)); - final NotificationManager notificationManager = - (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); - notificationManager.notifyAsUser(null, - SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION, - n.build(), UserHandle.ALL); - } - - // TODO: remove this toast after feature development is done - // show a toast message to ask user to file a bugreport so we know how many apps are impacted by - // the new background started foreground service while-in-use permission restriction. - void showWhileInUseDebugNotificationLocked(int uid, int op, int mode) { - StringBuilder packageNameBuilder = new StringBuilder(); - StringBuilder detailInfoBuilder = new StringBuilder(); + void showWhileInUseDebugToastLocked(int uid, int op, int mode) { for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); if (pr.uid != uid) { @@ -4732,18 +4937,8 @@ public final class ActiveServices { + " affected while-in-use permission:" + AppOpsManager.opToPublicName(op); Slog.wtf(TAG, msg); - packageNameBuilder.append(r.mRecentCallingPackage + " "); - detailInfoBuilder.append(msg); - detailInfoBuilder.append("\n"); } } } - - final String callingPackageStr = packageNameBuilder.toString(); - if (mAm.mConstants.mFlagForegroundServiceStartsLoggingEnabled - && !callingPackageStr.isEmpty()) { - showWhileInUsePermissionInFgsBlockedNotificationLocked(callingPackageStr, - detailInfoBuilder.toString()); - } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index cea3bb83deb0..fbcb0102eb47 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -65,6 +65,10 @@ import static android.os.Process.SHELL_UID; import static android.os.Process.SIGNAL_USR1; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_FOREGROUND; +import static android.os.Process.ZYGOTE_POLICY_FLAG_BATCH_LAUNCH; +import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; +import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; +import static android.os.Process.ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS; import static android.os.Process.ZYGOTE_PROCESS; import static android.os.Process.getTotalMemory; import static android.os.Process.isThreadInProcess; @@ -3054,7 +3058,7 @@ public class ActivityManagerService extends IActivityManager.Stub info.targetSdkVersion = Build.VERSION.SDK_INT; ProcessRecord proc = mProcessList.startProcessLocked(processName, info /* info */, false /* knownToBeDead */, 0 /* intentFlags */, - sNullHostingRecord /* hostingRecord */, + sNullHostingRecord /* hostingRecord */, ZYGOTE_POLICY_FLAG_EMPTY, true /* allowWhileBooting */, true /* isolated */, uid, true /* keepIfLarge */, abiOverride, entryPoint, entryPointArgs, crashHandler); @@ -3065,12 +3069,12 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, - HostingRecord hostingRecord, boolean allowWhileBooting, + HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags, - hostingRecord, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, - null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, - null /* crashHandler */); + hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */, + keepIfLarge, null /* ABI override */, null /* entryPoint */, + null /* entryPointArgs */, null /* crashHandler */); } boolean isAllowedWhileBooting(ApplicationInfo ai) { @@ -4953,7 +4957,8 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (RemoteException e) { app.resetPackageList(mProcessStats); mProcessList.startProcessLocked(app, - new HostingRecord("link fail", processName)); + new HostingRecord("link fail", processName), + ZYGOTE_POLICY_FLAG_EMPTY); return false; } @@ -5372,7 +5377,9 @@ public class ActivityManagerService extends IActivityManager.Stub for (int ip=0; ip<NP; ip++) { if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Starting process on hold: " + procs.get(ip)); - mProcessList.startProcessLocked(procs.get(ip), new HostingRecord("on-hold")); + mProcessList.startProcessLocked(procs.get(ip), + new HostingRecord("on-hold"), + ZYGOTE_POLICY_FLAG_BATCH_LAUNCH); } } if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) { @@ -6515,14 +6522,6 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds, - Rect tempDockedTaskInsetBounds, - Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) { - mActivityTaskManager.resizeDockedStack(dockedBounds, tempDockedTaskBounds, - tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds); - } - - @Override public void positionTaskInStack(int taskId, int stackId, int position) { mActivityTaskManager.positionTaskInStack(taskId, stackId, position); } @@ -7232,8 +7231,9 @@ public class ActivityManagerService extends IActivityManager.Stub proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, new HostingRecord("content provider", - new ComponentName(cpi.applicationInfo.packageName, - cpi.name)), false, false, false); + new ComponentName(cpi.applicationInfo.packageName, + cpi.name)), + ZYGOTE_POLICY_FLAG_EMPTY, false, false, false); checkTime(startTime, "getContentProviderImpl: after start process"); if (proc == null) { Slog.w(TAG, "Unable to launch app " @@ -7267,10 +7267,8 @@ public class ActivityManagerService extends IActivityManager.Stub } checkTime(startTime, "getContentProviderImpl: done!"); - grantImplicitAccess(userId, null /*intent*/, - UserHandle.getAppId(Binder.getCallingUid()), - UserHandle.getAppId(cpi.applicationInfo.uid) - ); + grantImplicitAccess(userId, null /*intent*/, callingUid, + UserHandle.getAppId(cpi.applicationInfo.uid)); } // Wait for the provider to be published... @@ -7793,7 +7791,8 @@ public class ActivityManagerService extends IActivityManager.Stub .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList(); for (ApplicationInfo app : apps) { if (!"android".equals(app.packageName)) { - addAppLocked(app, null, false, null /* ABI override */); + addAppLocked(app, null, false, null /* ABI override */, + ZYGOTE_POLICY_FLAG_BATCH_LAUNCH); } } } catch (RemoteException ex) { @@ -8064,23 +8063,25 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, - String abiOverride) { + String abiOverride, int zygotePolicyFlags) { return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */, - false /* mountExtStorageFull */, abiOverride); + false /* mountExtStorageFull */, abiOverride, zygotePolicyFlags); } @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, - boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride) { + boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride, + int zygotePolicyFlags) { return addAppLocked(info, customProcess, isolated, disableHiddenApiChecks, - false /* disableTestApiChecks */, mountExtStorageFull, abiOverride); + false /* disableTestApiChecks */, mountExtStorageFull, abiOverride, + zygotePolicyFlags); } // TODO: Move to ProcessList? @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, boolean disableHiddenApiChecks, boolean disableTestApiChecks, - boolean mountExtStorageFull, String abiOverride) { + boolean mountExtStorageFull, String abiOverride, int zygotePolicyFlags) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName, @@ -8115,7 +8116,8 @@ public class ActivityManagerService extends IActivityManager.Stub mPersistentStartingProcesses.add(app); mProcessList.startProcessLocked(app, new HostingRecord("added application", customProcess != null ? customProcess : app.processName), - disableHiddenApiChecks, disableTestApiChecks, mountExtStorageFull, abiOverride); + zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks, + mountExtStorageFull, abiOverride); } return app; @@ -14622,7 +14624,8 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.addProcessNameLocked(app); app.pendingStart = false; mProcessList.startProcessLocked(app, - new HostingRecord("restart", app.processName)); + new HostingRecord("restart", app.processName), + ZYGOTE_POLICY_FLAG_EMPTY); return true; } else if (app.pid > 0 && app.pid != MY_PID) { // Goodbye! @@ -14985,7 +14988,7 @@ public class ActivityManagerService extends IActivityManager.Stub ProcessRecord proc = startProcessLocked(app.processName, app, false, 0, new HostingRecord("backup", hostingName), - false, false, false); + ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false, false); if (proc == null) { Slog.e(TAG, "Unable to start backup agent process " + r); return false; @@ -16624,7 +16627,8 @@ public class ActivityManagerService extends IActivityManager.Stub } ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, - disableTestApiChecks, mountExtStorageFull, abiOverride); + disableTestApiChecks, mountExtStorageFull, abiOverride, + ZYGOTE_POLICY_FLAG_EMPTY); app.setActiveInstrumentation(activeInstr); activeInstr.mFinished = false; activeInstr.mSourceUid = callingUid; @@ -18021,7 +18025,8 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.mRemovedProcesses.remove(i); if (app.isPersistent()) { - addAppLocked(app.info, null, false, null /* ABI override */); + addAppLocked(app.info, null, false, null /* ABI override */, + ZYGOTE_POLICY_FLAG_BATCH_LAUNCH); } } } @@ -19228,8 +19233,8 @@ public class ActivityManagerService extends IActivityManager.Stub // preempted by other processes before attaching the process of top app. startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */, new HostingRecord(hostingType, hostingName, isTop), - false /* allowWhileBooting */, false /* isolated */, - true /* keepIfLarge */); + ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */, + false /* isolated */, true /* keepIfLarge */); } } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -19347,7 +19352,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void showWhileInUseDebugToast(int uid, int op, int mode) { synchronized (ActivityManagerService.this) { - ActivityManagerService.this.mServices.showWhileInUseDebugNotificationLocked( + ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked( uid, op, mode); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index bf797291380a..59f64ac8c689 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1763,6 +1763,12 @@ final class ActivityManagerShellCommand extends ShellCommand { } private boolean switchUserAndWaitForComplete(int userId) throws RemoteException { + UserInfo currentUser = mInterface.getCurrentUser(); + if (currentUser != null && userId == currentUser.id) { + // Already switched to the correct user, exit early. + return true; + } + // Register switch observer. final CountDownLatch switchLatch = new CountDownLatch(1); mInterface.registerUserSwitchObserver( @@ -1777,13 +1783,18 @@ final class ActivityManagerShellCommand extends ShellCommand { // Switch. boolean switched = mInterface.switchUser(userId); + if (!switched) { + // Switching failed, don't wait for the user switch observer. + return false; + } // Wait. try { - switchLatch.await(USER_OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS); + switched = switchLatch.await(USER_OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { - getErrPrintWriter().println("Thread interrupted unexpectedly."); + getErrPrintWriter().println("Error: Thread interrupted unexpectedly."); } + return switched; } @@ -1815,7 +1826,7 @@ final class ActivityManagerShellCommand extends ShellCommand { if (switched) { return 0; } else { - pw.printf("Failed to switch to user %d\n", userId); + pw.printf("Error: Failed to switch to user %d\n", userId); return 1; } } @@ -2570,8 +2581,6 @@ final class ActivityManagerShellCommand extends ShellCommand { switch (op) { case "move-task": return runStackMoveTask(pw); - case "resize-docked-stack": - return runStackResizeDocked(pw); case "positiontask": return runStackPositionTask(pw); case "list": @@ -2646,17 +2655,6 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } - int runStackResizeDocked(PrintWriter pw) throws RemoteException { - final Rect bounds = getBounds(); - final Rect taskBounds = getBounds(); - if (bounds == null || taskBounds == null) { - getErrPrintWriter().println("Error: invalid input bounds"); - return -1; - } - mTaskInterface.resizeDockedStack(bounds, taskBounds, null, null, null); - return 0; - } - int runStackPositionTask(PrintWriter pw) throws RemoteException { String taskIdStr = getNextArgRequired(); int taskId = Integer.parseInt(taskIdStr); diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index 60aba277569b..cba6b92bf440 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -708,7 +708,7 @@ public final class AppExitInfoTracker { void dumpHistoryProcessExitInfo(PrintWriter pw, String packageName) { pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity exit-info)"); - SimpleDateFormat sdf = new SimpleDateFormat(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); synchronized (mLock) { pw.println("Last Timestamp of Persistence Into Persistent Storage: " + sdf.format(new Date(mLastAppExitInfoPersistTimestamp))); diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 119394fdadb8..dbad562c0271 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -17,7 +17,6 @@ package com.android.server.am; import android.app.ActivityManager; -import android.app.job.JobProtoEnums; import android.bluetooth.BluetoothActivityEnergyInfo; import android.content.ContentResolver; import android.content.Context; @@ -468,26 +467,18 @@ public final class BatteryStatsService extends IBatteryStats.Stub } /** A scheduled job was started. */ - public void noteJobStart(String name, int uid, int standbyBucket, int jobid) { + public void noteJobStart(String name, int uid) { enforceCallingPermission(); synchronized (mStats) { mStats.noteJobStartLocked(name, uid); - FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, - uid, null, name, - FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED, - JobProtoEnums.STOP_REASON_UNKNOWN, standbyBucket, jobid); } } /** A scheduled job was finished. */ - public void noteJobFinish(String name, int uid, int stopReason, int standbyBucket, int jobid) { + public void noteJobFinish(String name, int uid, int stopReason) { enforceCallingPermission(); synchronized (mStats) { mStats.noteJobFinishLocked(name, uid, stopReason); - FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, - uid, null, name, - FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED, stopReason, - standbyBucket, jobid); } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 26ef7073487d..3aec53a44058 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -16,6 +16,9 @@ package com.android.server.am; +import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; +import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; + import static com.android.server.am.ActivityManagerDebugConfig.*; import android.app.ActivityManager; @@ -1593,7 +1596,9 @@ public final class BroadcastQueue { + receiverUid); } - if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { + final boolean isActivityCapable = + (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0); + if (isActivityCapable) { scheduleTempWhitelistLocked(receiverUid, brOptions.getTemporaryAppWhitelistDuration(), r); } @@ -1648,6 +1653,7 @@ public final class BroadcastQueue { info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, new HostingRecord("broadcast", r.curComponent), + isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY, (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) { // Ah, this recipient is unavailable. Finish it if necessary, diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index eec68dc7353e..be483747d2cf 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -911,10 +911,12 @@ public final class CachedAppOptimizer { pid = proc.pid; name = proc.processName; - if (proc.curAdj <= ProcessList.CACHED_APP_MIN_ADJ) { + if (proc.curAdj < ProcessList.CACHED_APP_MIN_ADJ + || proc.shouldNotFreeze) { if (DEBUG_FREEZER) { Slog.d(TAG_AM, "Skipping freeze for process " + pid - + " " + name + " (not cached)"); + + " " + name + " curAdj = " + proc.curAdj + + ", shouldNotFreeze = " + proc.shouldNotFreeze); } return; } diff --git a/services/core/java/com/android/server/am/InstrumentationReporter.java b/services/core/java/com/android/server/am/InstrumentationReporter.java index fdbb73e9fa0e..729430860296 100644 --- a/services/core/java/com/android/server/am/InstrumentationReporter.java +++ b/services/core/java/com/android/server/am/InstrumentationReporter.java @@ -18,6 +18,7 @@ package com.android.server.am; import android.app.IInstrumentationWatcher; import android.content.ComponentName; +import android.os.Binder; import android.os.Bundle; import android.os.Process; import android.os.RemoteException; @@ -109,6 +110,8 @@ public class InstrumentationReporter { mName = name; mResultCode = resultCode; mResults = results; + + Binder.allowBlocking(mWatcher.asBinder()); } } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index c239feb155c6..3fd1b7830ba0 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1109,6 +1109,7 @@ public final class OomAdjuster { app.adjTarget = null; app.empty = false; app.setCached(false); + app.shouldNotFreeze = false; final int appUid = app.info.uid; final int logUid = mService.mCurOomAdjUid; @@ -1542,23 +1543,24 @@ public final class OomAdjuster { } boolean trackedProcState = false; - if ((cr.flags& Context.BIND_WAIVE_PRIORITY) == 0) { - ProcessRecord client = cr.binding.client; - if (computeClients) { - computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now, - cycleReEval, true); - } else { - client.setCurRawAdj(client.setAdj); - client.setCurRawProcState(client.setProcState); - } + ProcessRecord client = cr.binding.client; + if (computeClients) { + computeOomAdjLocked(client, cachedAdj, topApp, doingAll, now, + cycleReEval, true); + } else { + client.setCurRawAdj(client.setAdj); + client.setCurRawProcState(client.setProcState); + } + + int clientAdj = client.getCurRawAdj(); + int clientProcState = client.getCurRawProcState(); + + if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) { if (shouldSkipDueToCycle(app, client, procState, adj, cycleReEval)) { continue; } - int clientAdj = client.getCurRawAdj(); - int clientProcState = client.getCurRawProcState(); - if (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE) { procStateFromFGSClient = true; } @@ -1762,6 +1764,19 @@ public final class OomAdjuster { + ProcessList.makeProcStateString(procState)); } } + } else { // BIND_WAIVE_PRIORITY == true + // BIND_WAIVE_PRIORITY bindings are special when it comes to the + // freezer. Processes bound via WPRI are expected to be running, + // but they are not promoted in the LRU list to keep them out of + // cached. As a result, they can freeze based on oom_adj alone. + // Normally, bindToDeath would fire when a cached app would die + // in the background, but nothing will fire when a running process + // pings a frozen process. Accordingly, any cached app that is + // bound by an unfrozen app via a WPRI binding has to remain + // unfrozen. + if (clientAdj < ProcessList.CACHED_APP_MIN_ADJ) { + app.shouldNotFreeze = true; + } } if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { app.treatLikeActivity = true; diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 22559c426348..5d1b0e3924ea 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -25,6 +25,7 @@ import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrict import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; +import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY; import static android.os.Process.getFreeMemory; import static android.os.Process.getTotalMemory; import static android.os.Process.killProcessQuiet; @@ -80,13 +81,11 @@ import android.os.Bundle; import android.os.DropBoxManager; import android.os.Handler; import android.os.IBinder; -import android.os.IVold; import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; @@ -1640,7 +1639,7 @@ public final class ProcessList { */ @GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, - boolean disableHiddenApiChecks, boolean disableTestApiChecks, + int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks, boolean mountExtStorageFull, String abiOverride) { if (app.pendingStart) { return true; @@ -1733,8 +1732,7 @@ public final class ProcessList { } // Run the app in safe mode if its manifest requests so or the // system is booted in safe mode. - if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 || - mService.mSafeMode == true) { + if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 || mService.mSafeMode) { runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE; } if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0) { @@ -1846,8 +1844,8 @@ public final class ProcessList { final String entryPoint = "android.app.ActivityThread"; return startProcessLocked(hostingRecord, entryPoint, app, uid, gids, - runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, - startTime); + runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi, + instructionSet, invokeWith, startTime); } catch (RuntimeException e) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); @@ -1864,9 +1862,8 @@ public final class ProcessList { } @GuardedBy("mService") - boolean startProcessLocked(HostingRecord hostingRecord, - String entryPoint, - ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, + boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, + int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { app.pendingStart = true; @@ -1895,15 +1892,15 @@ public final class ProcessList { if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES, "Posting procStart msg for " + app.toShortString()); mService.mProcStartHandler.post(() -> handleProcessStart( - app, entryPoint, gids, runtimeFlags, mountExternal, requiredAbi, - instructionSet, invokeWith, startSeq)); + app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal, + requiredAbi, instructionSet, invokeWith, startSeq)); return true; } else { try { final Process.ProcessStartResult startResult = startProcess(hostingRecord, entryPoint, app, - uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, - invokeWith, startTime); + uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, + requiredAbi, instructionSet, invokeWith, startTime); handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper, startSeq, false); } catch (RuntimeException e) { @@ -1923,8 +1920,8 @@ public final class ProcessList { * <p>Note: this function doesn't hold the global AM lock intentionally.</p> */ private void handleProcessStart(final ProcessRecord app, final String entryPoint, - final int[] gids, final int runtimeFlags, final int mountExternal, - final String requiredAbi, final String instructionSet, + final int[] gids, final int runtimeFlags, int zygotePolicyFlags, + final int mountExternal, final String requiredAbi, final String instructionSet, final String invokeWith, final long startSeq) { // If there is a precede instance of the process, wait for its death with a timeout. // Use local reference since we are not using locks here @@ -1959,8 +1956,10 @@ public final class ProcessList { } try { final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, - entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, - app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); + entryPoint, app, app.startUid, gids, runtimeFlags, zygotePolicyFlags, + mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, + app.startTime); + synchronized (mService) { handleProcessStartedLocked(app, startResult, startSeq); } @@ -2113,9 +2112,9 @@ public final class ProcessList { } private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint, - ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, - String seInfo, String requiredAbi, String instructionSet, String invokeWith, - long startTime) { + ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, + int mountExternal, String seInfo, String requiredAbi, String instructionSet, + String invokeWith, long startTime) { try { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); @@ -2163,14 +2162,15 @@ public final class ProcessList { app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, - /*useUsapPool=*/ false, isTopApp, app.mDisabledCompatChanges, - pkgDataInfoMap, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); + /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, + app.mDisabledCompatChanges, pkgDataInfoMap, + new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, - app.info.dataDir, invokeWith, app.info.packageName, isTopApp, - app.mDisabledCompatChanges, pkgDataInfoMap, + app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, + isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } checkSlow(startTime, "startProcess: returned from zygote!"); @@ -2181,14 +2181,14 @@ public final class ProcessList { } @GuardedBy("mService") - final void startProcessLocked(ProcessRecord app, HostingRecord hostingRecord) { - startProcessLocked(app, hostingRecord, null /* abiOverride */); + void startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags) { + startProcessLocked(app, hostingRecord, zygotePolicyFlags, null /* abiOverride */); } @GuardedBy("mService") final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, - String abiOverride) { - return startProcessLocked(app, hostingRecord, + int zygotePolicyFlags, String abiOverride) { + return startProcessLocked(app, hostingRecord, zygotePolicyFlags, false /* disableHiddenApiChecks */, false /* disableTestApiChecks */, false /* mountExtStorageFull */, abiOverride); } @@ -2196,8 +2196,9 @@ public final class ProcessList { @GuardedBy("mService") final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, - boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, - String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { + int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid, + boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, + Runnable crashHandler) { long startTime = SystemClock.uptimeMillis(); ProcessRecord app; if (!isolated) { @@ -2308,7 +2309,8 @@ public final class ProcessList { } checkSlow(startTime, "startProcess: stepping in to startProcess"); - final boolean success = startProcessLocked(app, hostingRecord, abiOverride); + final boolean success = + startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride); checkSlow(startTime, "startProcess: done starting proc!"); return success ? app : null; } @@ -2332,6 +2334,19 @@ public final class ProcessList { if (sb == null) sb = new StringBuilder(); sb.append("seq=" + app.startSeq + ",expected=" + expectedStartSeq + ";"); } + try { + AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, app.userId); + } catch (RemoteException e) { + // unexpected; ignore + } catch (SecurityException e) { + if (mService.mConstants.FLAG_PROCESS_START_ASYNC) { + if (sb == null) sb = new StringBuilder(); + sb.append("Package is frozen;"); + } else { + // we're not being started async and so should throw to the caller. + throw e; + } + } return sb == null ? null : sb.toString(); } @@ -2631,7 +2646,8 @@ public final class ProcessList { mService.handleAppDiedLocked(app, willRestart, allowRestart); if (willRestart) { removeLruProcessLocked(app); - mService.addAppLocked(app.info, null, false, null /* ABI override */); + mService.addAppLocked(app.info, null, false, null /* ABI override */, + ZYGOTE_POLICY_FLAG_EMPTY); } } else { mRemovedProcesses.add(app); diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index c2f03ec8d6c4..f2ca1daec306 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -167,6 +167,7 @@ class ProcessRecord implements WindowProcessListener { int lastCompactAction; // The most recent compaction action performed for this app. boolean frozen; // True when the process is frozen. long freezeUnfreezeTime; // Last time the app was (un)frozen, 0 for never + boolean shouldNotFreeze; // True if a process has a WPRI binding from an unfrozen process private int mCurSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class int trimMemoryLevel; // Last selected memory trimming level diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 5b8a6d935d30..c15360b00d51 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -4060,9 +4060,11 @@ public class AppOpsService extends IAppOpsService.Stub { private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException, XmlPullParserException, IOException { - Op op = new Op(uidState, pkgName, - Integer.parseInt(parser.getAttributeValue(null, "n")), - uidState.uid); + int opCode = Integer.parseInt(parser.getAttributeValue(null, "n")); + if (isIgnoredAppOp(opCode)) { + return; + } + Op op = new Op(uidState, pkgName, opCode, uidState.uid); final int mode = XmlUtils.readIntAttribute(parser, "m", AppOpsManager.opToDefaultMode(op.op)); @@ -4096,6 +4098,16 @@ public class AppOpsService extends IAppOpsService.Stub { ops.put(op.op, op); } + //TODO(b/149995538): Remove once this has reached all affected devices + private static boolean isIgnoredAppOp(int op) { + switch (op) { + case AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE: + return true; + default: + return false; + } + } + void writeState() { synchronized (mFile) { FileOutputStream stream; diff --git a/services/core/java/com/android/server/backup/PeopleBackupHelper.java b/services/core/java/com/android/server/backup/PeopleBackupHelper.java index e58a051544d8..555e0069b0b3 100644 --- a/services/core/java/com/android/server/backup/PeopleBackupHelper.java +++ b/services/core/java/com/android/server/backup/PeopleBackupHelper.java @@ -50,7 +50,7 @@ class PeopleBackupHelper extends BlobBackupHelper { if (DEBUG) { Slog.d(TAG, "Handling backup of " + key); } - return ps.backupConversationInfos(mUserId); + return ps.getBackupPayload(mUserId); } @Override @@ -63,6 +63,6 @@ class PeopleBackupHelper extends BlobBackupHelper { if (DEBUG) { Slog.d(TAG, "Handling restore of " + key); } - ps.restoreConversationInfos(mUserId, key, payload); + ps.restore(mUserId, payload); } } diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 7f7c9c4c7c1d..441d9d9f380e 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -16,6 +16,7 @@ package com.android.server.compat; +import android.app.compat.ChangeIdStateCache; import android.compat.Compatibility.ChangeConfig; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -80,6 +81,7 @@ final class CompatConfig { void addChange(CompatChange change) { synchronized (mChanges) { mChanges.put(change.getId(), change); + invalidateCache(); } } @@ -172,6 +174,7 @@ final class CompatConfig { addChange(c); } c.addPackageOverride(packageName, enabled); + invalidateCache(); } return alreadyKnown; } @@ -228,6 +231,7 @@ final class CompatConfig { // Should never occur, since validator is in the same process. throw new RuntimeException("Unable to call override validator!", e); } + invalidateCache(); } return overrideExists; } @@ -250,6 +254,7 @@ final class CompatConfig { addOverride(changeId, packageName, false); } + invalidateCache(); } } @@ -279,6 +284,7 @@ final class CompatConfig { throw new RuntimeException("Unable to call override validator!", e); } } + invalidateCache(); } } @@ -377,6 +383,7 @@ final class CompatConfig { config.initConfigFromLib(Environment.buildPath( apex.apexDirectory, "etc", "compatconfig")); } + config.invalidateCache(); return config; } @@ -406,4 +413,8 @@ final class CompatConfig { IOverrideValidator getOverrideValidator() { return mOverrideValidator; } + + private void invalidateCache() { + ChangeIdStateCache.invalidate(); + } } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 7cb84585a57c..612fd39634ea 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -178,6 +178,8 @@ public class DisplayModeDirector { float maxRefreshRate = Float.POSITIVE_INFINITY; int lowestConsideredPriority = Vote.MIN_PRIORITY; while (lowestConsideredPriority <= Vote.MAX_PRIORITY) { + minRefreshRate = 0f; + maxRefreshRate = Float.POSITIVE_INFINITY; int height = Vote.INVALID_SIZE; int width = Vote.INVALID_SIZE; diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index e578ac1fcd42..05a757bde179 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -181,6 +181,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { private int mState = Display.STATE_UNKNOWN; private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; private int mDefaultModeId; + private int mDefaultConfigGroup; private int mActiveModeId; private boolean mActiveModeInvalid; private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs = @@ -332,15 +333,18 @@ final class LocalDisplayAdapter extends DisplayAdapter { // For a new display, we need to initialize the default mode ID. if (mDefaultModeId == NO_DISPLAY_MODE_ID) { mDefaultModeId = activeRecord.mMode.getModeId(); + mDefaultConfigGroup = configs[activeConfigId].configGroup; } else if (modesAdded && mActiveModeId != activeRecord.mMode.getModeId()) { Slog.d(TAG, "New display modes are added and the active mode has changed, " + "use active mode as default mode."); mActiveModeId = activeRecord.mMode.getModeId(); mDefaultModeId = activeRecord.mMode.getModeId(); - } else if (findDisplayConfigIdLocked(mDefaultModeId) < 0) { + mDefaultConfigGroup = configs[activeConfigId].configGroup; + } else if (findDisplayConfigIdLocked(mDefaultModeId, mDefaultConfigGroup) < 0) { Slog.w(TAG, "Default display mode no longer available, using currently" + " active mode as default."); mDefaultModeId = activeRecord.mMode.getModeId(); + mDefaultConfigGroup = configs[activeConfigId].configGroup; } // Determine whether the display mode specs' base mode is still there. @@ -754,7 +758,16 @@ final class LocalDisplayAdapter extends DisplayAdapter { // a valid mode. return; } - int baseConfigId = findDisplayConfigIdLocked(displayModeSpecs.baseModeId); + + // Find the config Id based on the desired mode specs. In case there is more than one + // config matching the mode spec, prefer the one that is in the default config group. + // For now the default config group is taken from the active config when we got the + // hotplug event for the display. In the future we might want to change the default + // config based on vendor requirements. + // Note: We prefer the default config group over the current one as this is the config + // group the vendor prefers. + int baseConfigId = findDisplayConfigIdLocked(displayModeSpecs.baseModeId, + mDefaultConfigGroup); if (baseConfigId < 0) { // When a display is hotplugged, it's possible for a mode to be removed that was // previously valid. Because of the way display changes are propagated through the @@ -906,17 +919,26 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.print("mSupportedColorModes=" + mSupportedColorModes.toString()); } - private int findDisplayConfigIdLocked(int modeId) { + private int findDisplayConfigIdLocked(int modeId, int configGroup) { + int matchingConfigId = SurfaceControl.DisplayConfig.INVALID_DISPLAY_CONFIG_ID; DisplayModeRecord record = mSupportedModes.get(modeId); if (record != null) { for (int i = 0; i < mDisplayConfigs.length; i++) { SurfaceControl.DisplayConfig config = mDisplayConfigs[i]; if (record.hasMatchingMode(config)) { - return i; + if (matchingConfigId + == SurfaceControl.DisplayConfig.INVALID_DISPLAY_CONFIG_ID) { + matchingConfigId = i; + } + + // Prefer to return a config that matches the configGroup + if (config.configGroup == configGroup) { + return i; + } } } } - return -1; + return matchingConfigId; } private int findMatchingModeIdLocked(int configId) { diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java index a8121cc6924f..1320e6c911a0 100644 --- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java +++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java @@ -26,9 +26,7 @@ import android.content.pm.IDataLoader; import android.content.pm.IDataLoaderStatusListener; import android.os.Bundle; import android.os.RemoteException; -import android.os.ResultReceiver; import android.os.ServiceManager; -import android.os.ShellCallback; import android.os.incremental.IIncrementalManager; import android.util.Slog; @@ -147,14 +145,6 @@ public class IncrementalManagerService extends IIncrementalManager.Stub { // TODO(b/136132412): implement this } - @Override - public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, - FileDescriptor err, @NonNull String[] args, ShellCallback callback, - @NonNull ResultReceiver resultReceiver) { - (new IncrementalManagerShellCommand(mContext)).exec( - this, in, out, err, args, callback, resultReceiver); - } - private static native long nativeStartService(); private static native void nativeSystemReady(long nativeInstance); diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java b/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java deleted file mode 100644 index 6a5e963064bb..000000000000 --- a/services/core/java/com/android/server/incremental/IncrementalManagerShellCommand.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.incremental; - -import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.content.Context; -import android.content.IIntentReceiver; -import android.content.IIntentSender; -import android.content.Intent; -import android.content.IntentSender; -import android.content.pm.DataLoaderParams; -import android.content.pm.InstallationFile; -import android.content.pm.PackageInstaller; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.ShellCommand; -import android.util.Slog; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - -/** - * Defines actions to handle adb commands like "adb abb incremental ...". - */ -public final class IncrementalManagerShellCommand extends ShellCommand { - private static final String TAG = "IncrementalShellCommand"; - // Assuming the adb data loader is always installed on the device - private static final String LOADER_PACKAGE_NAME = "com.android.incremental.nativeadb"; - private static final String LOADER_CLASS_NAME = - LOADER_PACKAGE_NAME + ".NativeAdbDataLoaderService"; - private final @NonNull Context mContext; - - private static final int ERROR_INVALID_ARGUMENTS = -1; - private static final int ERROR_DATA_LOADER_INIT = -2; - private static final int ERROR_COMMAND_EXECUTION = -3; - - @Retention(RetentionPolicy.SOURCE) - @IntDef({ERROR_INVALID_ARGUMENTS, ERROR_DATA_LOADER_INIT, ERROR_COMMAND_EXECUTION}) - public @interface IncrementalShellCommandErrorCode { - } - - IncrementalManagerShellCommand(@NonNull Context context) { - mContext = context; - } - - @Override - public int onCommand(@Nullable String cmd) { - if (cmd == null) { - return handleDefaultCommands(null); - } - switch (cmd) { - case "install-start": - return runInstallStart(); - case "install-finish": - return runInstallFinish(); - default: - return handleDefaultCommands(cmd); - } - } - - @Override - public void onHelp() { - PrintWriter pw = getOutPrintWriter(); - pw.println("Incremental Service Commands:"); - pw.println(" help"); - pw.println(" Print this help text."); - pw.println(" install-start"); - pw.println(" Opens an installation session"); - pw.println(" install-finish SESSION_ID --file NAME:SIZE:INDEX --file NAME:SIZE:INDEX ..."); - pw.println(" Commits an installation session specified by session ID for an APK "); - pw.println(" or a bundle of splits. Configures lib dirs or OBB files if specified."); - } - - private int runInstallStart() { - final PrintWriter pw = getOutPrintWriter(); - final PackageInstaller packageInstaller = - mContext.getPackageManager().getPackageInstaller(); - if (packageInstaller == null) { - pw.println("Failed to get PackageInstaller."); - return ERROR_COMMAND_EXECUTION; - } - - final Map<String, ParcelFileDescriptor> fds = getShellFileDescriptors(); - if (fds == null) { - pw.println("File names and sizes don't match."); - return ERROR_DATA_LOADER_INIT; - } - // dup FDs before closing them - final Map<String, ParcelFileDescriptor> dataLoaderDynamicArgs = new HashMap<>(); - for (Map.Entry<String, ParcelFileDescriptor> nfd : fds.entrySet()) { - try { - dataLoaderDynamicArgs.put(nfd.getKey(), nfd.getValue().dup()); - } catch (IOException ignored) { - pw.println("Failed to dup shell file descriptor"); - return ERROR_DATA_LOADER_INIT; - } finally { - try { - nfd.getValue().close(); - } catch (IOException ignored) { - } - } - } - - final DataLoaderParams params = DataLoaderParams.forIncremental( - new ComponentName(LOADER_PACKAGE_NAME, LOADER_CLASS_NAME), "", - dataLoaderDynamicArgs); - PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams( - PackageInstaller.SessionParams.MODE_FULL_INSTALL); - sessionParams.installFlags |= PackageManager.INSTALL_ALL_USERS; - // Replace existing if same package is already installed - sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; - sessionParams.setDataLoaderParams(params); - - try { - int sessionId = packageInstaller.createSession(sessionParams); - pw.println("Successfully opened session: sessionId = " + sessionId); - } catch (IOException ex) { - pw.println("Failed to create session."); - return ERROR_COMMAND_EXECUTION; - } - return 0; - } - - private int runInstallFinish() { - final PrintWriter pw = getOutPrintWriter(); - final int sessionId = parseInt(getNextArgRequired()); - final List<InstallationFile> installationFiles = parseFileArgs(pw); - if (installationFiles == null) { - pw.println("Must specify at least one file to install."); - return ERROR_INVALID_ARGUMENTS; - } - final int numFiles = installationFiles.size(); - if (numFiles == 0) { - pw.println("Must specify at least one file to install."); - return ERROR_INVALID_ARGUMENTS; - } - - final PackageInstaller packageInstaller = mContext.getPackageManager() - .getPackageInstaller(); - if (packageInstaller == null) { - pw.println("Failed to get PackageInstaller."); - return ERROR_COMMAND_EXECUTION; - } - - final LocalIntentReceiver localReceiver = new LocalIntentReceiver(); - boolean success = false; - - PackageInstaller.Session session = null; - try { - session = packageInstaller.openSession(sessionId); - for (int i = 0; i < numFiles; i++) { - InstallationFile file = installationFiles.get(i); - session.addFile(file.getLocation(), file.getName(), file.getLengthBytes(), - file.getMetadata(), file.getSignature()); - } - session.commit(localReceiver.getIntentSender()); - final Intent result = localReceiver.getResult(); - final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status == PackageInstaller.STATUS_SUCCESS) { - success = true; - pw.println("Success"); - return 0; - } else { - pw.println("Failure [" - + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); - return ERROR_COMMAND_EXECUTION; - } - } catch (Exception e) { - e.printStackTrace(pw); - return ERROR_COMMAND_EXECUTION; - } finally { - if (!success) { - try { - if (session != null) { - session.abandon(); - } - } catch (Exception ignore) { - } - } - } - } - - private static class LocalIntentReceiver { - private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>(); - - private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { - @Override - public void send(int code, Intent intent, String resolvedType, - IBinder whitelistToken, - IIntentReceiver finishedReceiver, String requiredPermission, - Bundle options) { - try { - mResult.offer(intent, 5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - }; - - public IntentSender getIntentSender() { - return new IntentSender((IIntentSender) mLocalSender); - } - - public Intent getResult() { - try { - return mResult.take(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - - /** Helpers. */ - private Map<String, ParcelFileDescriptor> getShellFileDescriptors() { - Map<String, ParcelFileDescriptor> fds = new HashMap<>(); - final FileDescriptor outFd = getOutFileDescriptor(); - final FileDescriptor inFd = getInFileDescriptor(); - try { - fds.put("inFd", ParcelFileDescriptor.dup(inFd)); - fds.put("outFd", ParcelFileDescriptor.dup(outFd)); - return fds; - } catch (Exception ex) { - Slog.e(TAG, "Failed to dup FDs"); - return null; - } - } - - private long parseLong(String arg) { - long result = -1; - try { - result = Long.parseLong(arg); - } catch (NumberFormatException e) { - } - return result; - } - - private int parseInt(String arg) { - int result = -1; - try { - result = Integer.parseInt(arg); - } catch (NumberFormatException e) { - } - return result; - } - - private List<InstallationFile> parseFileArgs(PrintWriter pw) { - List<InstallationFile> fileList = new ArrayList<>(); - String opt; - while ((opt = getNextOption()) != null) { - switch (opt) { - case "--file": { - final String fileArgs = getNextArgRequired(); - final String[] args = fileArgs.split(":"); - if (args.length != 3) { - pw.println("Invalid file args: " + fileArgs); - return null; - } - final String name = args[0]; - final long size = parseLong(args[1]); - if (size < 0) { - pw.println("Invalid file size in: " + fileArgs); - return null; - } - final long index = parseLong(args[2]); - if (index < 0) { - pw.println("Invalid file index in: " + fileArgs); - return null; - } - final byte[] metadata = String.valueOf(index).getBytes( - StandardCharsets.UTF_8); - fileList.add( - new InstallationFile(LOCATION_DATA_APP, name, size, metadata, null)); - break; - } - default: - break; - } - } - return fileList; - } -} diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index f24699a6ae64..68e6c1885ec2 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -44,12 +44,6 @@ public abstract class InputMethodManagerInternal { } /** - * Called by the power manager to tell the input method manager whether it - * should start watching for wake events. - */ - public abstract void setInteractive(boolean interactive); - - /** * Hides the current input method, if visible. */ public abstract void hideCurrentInputMethod(@SoftInputShowHideReason int reason); @@ -103,10 +97,6 @@ public abstract class InputMethodManagerInternal { private static final InputMethodManagerInternal NOP = new InputMethodManagerInternal() { @Override - public void setInteractive(boolean interactive) { - } - - @Override public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) { } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index e3c545c3cf28..eab339374d56 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -846,6 +846,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final WeakHashMap<IBinder, IBinder> mShowRequestWindowMap = new WeakHashMap<>(); /** + * Map of generated token to windowToken that is requesting + * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}. + * This map tracks origin of hideSoftInput requests. + */ + @GuardedBy("mMethodMap") + private final WeakHashMap<IBinder, IBinder> mHideRequestWindowMap = new WeakHashMap<>(); + + /** * A ring buffer to store the history of {@link StartInputInfo}. */ private static final class StartInputHistory { @@ -1064,7 +1072,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub == AccessibilityService.SHOW_MODE_HIDDEN; if (mAccessibilityRequestingNoSoftKeyboard) { final boolean showRequested = mShowRequested; - hideCurrentInputLocked(0, null, + hideCurrentInputLocked(mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE); mShowRequested = showRequested; } else if (mShowRequested) { @@ -1695,7 +1703,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // TODO: Is it really possible that switchUserLocked() happens before system ready? if (mSystemReady) { - hideCurrentInputLocked(0, null, SoftInputShowHideReason.HIDE_SWITCH_USER); + hideCurrentInputLocked( + mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_SWITCH_USER); + resetCurrentMethodAndClient(UnbindReason.SWITCH_USER); buildInputMethodListLocked(initialUserSwitch); if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) { @@ -3040,7 +3050,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public boolean hideSoftInput(IInputMethodClient client, int flags, + public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, int flags, ResultReceiver resultReceiver) { int uid = Binder.getCallingUid(); synchronized (mMethodMap) { @@ -3068,7 +3078,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (DEBUG) Slog.v(TAG, "Client requesting input be hidden"); - return hideCurrentInputLocked(flags, resultReceiver, + return hideCurrentInputLocked(windowToken, flags, resultReceiver, SoftInputShowHideReason.HIDE_SOFT_INPUT); } finally { Binder.restoreCallingIdentity(ident); @@ -3076,7 +3086,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver, + boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0 && (mShowExplicitlyRequested || mShowForced)) { @@ -3100,12 +3110,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); boolean res; if (shouldHideSoftInput) { + final Binder hideInputToken = new Binder(); + mHideRequestWindowMap.put(hideInputToken, windowToken); // The IME will report its visible state again after the following message finally // delivered to the IME process as an IPC. Hence the inconsistency between // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in // the final state. - executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(MSG_HIDE_SOFT_INPUT, - reason, mCurMethod, resultReceiver)); + executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOOO(MSG_HIDE_SOFT_INPUT, + reason, mCurMethod, resultReceiver, hideInputToken)); res = true; } else { res = false; @@ -3242,7 +3254,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.w(TAG, "If you need to impersonate a foreground user/profile from" + " a background user, use EditorInfo.targetInputMethodUser with" + " INTERACT_ACROSS_USERS_FULL permission."); - hideCurrentInputLocked(0, null, SoftInputShowHideReason.HIDE_INVALID_USER); + hideCurrentInputLocked( + mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_INVALID_USER); return InputBindResult.INVALID_USER; } @@ -3305,7 +3318,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // be behind any soft input window, so hide the // soft input window if it is shown. if (DEBUG) Slog.v(TAG, "Unspecified window will hide input"); - hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null, + hideCurrentInputLocked( + mCurFocusedWindow, InputMethodManager.HIDE_NOT_ALWAYS, null, SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW); // If focused display changed, we should unbind current method @@ -3342,13 +3356,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub case LayoutParams.SOFT_INPUT_STATE_HIDDEN: if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) { if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward"); - hideCurrentInputLocked(0, null, + hideCurrentInputLocked(mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_STATE_HIDDEN_FORWARD_NAV); } break; case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN: if (DEBUG) Slog.v(TAG, "Window asks to hide input"); - hideCurrentInputLocked(0, null, + hideCurrentInputLocked(mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE); break; case LayoutParams.SOFT_INPUT_STATE_VISIBLE: @@ -3832,7 +3846,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Send it to window manager to hide IME from IME target window. // TODO(b/139861270): send to mCurClient.client once IMMS is aware of // actual IME target. - mWindowManagerInternal.hideIme(mCurClient.selfReportedDisplayId); + mWindowManagerInternal.hideIme(mHideRequestWindowMap.get(windowToken)); } } else { // Send to window manager to show IME after IME layout finishes. @@ -3872,7 +3886,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } long ident = Binder.clearCallingIdentity(); try { - hideCurrentInputLocked(flags, null, SoftInputShowHideReason.HIDE_MY_SOFT_INPUT); + hideCurrentInputLocked( + mLastImeTargetWindow, flags, null, + SoftInputShowHideReason.HIDE_MY_SOFT_INPUT); + } finally { Binder.restoreCallingIdentity(ident); } @@ -3969,11 +3986,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub args.recycle(); return true; case MSG_SHOW_SOFT_INPUT: - args = (SomeArgs)msg.obj; + args = (SomeArgs) msg.obj; try { final @SoftInputShowHideReason int reason = msg.arg2; if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput(" - + msg.arg1 + ", " + args.arg2 + ") for reason: " + + args.arg3 + ", " + msg.arg1 + ", " + args.arg2 + ") for reason: " + InputMethodDebug.softInputDisplayReasonToString(reason)); ((IInputMethod) args.arg1).showSoftInput( (IBinder) args.arg3, msg.arg1, (ResultReceiver) args.arg2); @@ -3986,13 +4003,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub args.recycle(); return true; case MSG_HIDE_SOFT_INPUT: - args = (SomeArgs)msg.obj; + args = (SomeArgs) msg.obj; try { final @SoftInputShowHideReason int reason = msg.arg1; if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, " - + args.arg2 + ") for reason: " + + args.arg3 + ", " + args.arg2 + ") for reason: " + InputMethodDebug.softInputDisplayReasonToString(reason)); - ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2); + ((IInputMethod)args.arg1).hideSoftInput( + (IBinder) args.arg3, 0, (ResultReceiver)args.arg2); mSoftInputShowHideHistory.addEntry( new SoftInputShowHideHistory.Entry(mCurClient, InputMethodDebug.objToString(mCurFocusedWindow), @@ -4004,7 +4022,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub case MSG_HIDE_CURRENT_INPUT_METHOD: synchronized (mMethodMap) { final @SoftInputShowHideReason int reason = (int) msg.obj; - hideCurrentInputLocked(0, null, reason); + hideCurrentInputLocked(mCurFocusedWindow, 0, null, reason); + } return true; case MSG_INITIALIZE_IME: @@ -4094,9 +4113,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + ((ClientState)msg.obj).uid); } return true; - case MSG_SET_INTERACTIVE: - handleSetInteractive(msg.arg1 != 0); - return true; case MSG_REPORT_FULLSCREEN_MODE: { final boolean fullscreen = msg.arg1 != 0; final ClientState clientState = (ClientState)msg.obj; @@ -4171,20 +4187,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return false; } - private void handleSetInteractive(final boolean interactive) { - synchronized (mMethodMap) { - mIsInteractive = interactive; - updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition); - - // Inform the current client of the change in active status - if (mCurClient != null && mCurClient.client != null) { - executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIIO( - MSG_SET_ACTIVE, mIsInteractive ? 1 : 0, mInFullscreenMode ? 1 : 0, - mCurClient)); - } - } - } - private boolean chooseNewDefaultIMELocked() { final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME( mSettings.getEnabledInputMethodListLocked()); @@ -4781,13 +4783,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public void setInteractive(boolean interactive) { - // Do everything in handler so as not to block the caller. - mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0) - .sendToTarget(); - } - - @Override public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) { mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD); mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget(); @@ -5409,7 +5404,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final String nextIme; final List<InputMethodInfo> nextEnabledImes; if (userId == mSettings.getCurrentUserId()) { - hideCurrentInputLocked(0, null, + hideCurrentInputLocked(mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND); unbindCurrentMethodLocked(); // Reset the current IME diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 1aff23b09c0f..0e6c0dbbca2d 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -170,11 +170,6 @@ public final class MultiClientInputMethodManagerService { LocalServices.addService(InputMethodManagerInternal.class, new InputMethodManagerInternal() { @Override - public void setInteractive(boolean interactive) { - reportNotSupported(); - } - - @Override public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) { reportNotSupported(); } @@ -1500,7 +1495,8 @@ public final class MultiClientInputMethodManagerService { @BinderThread @Override public boolean hideSoftInput( - IInputMethodClient client, int flags, ResultReceiver resultReceiver) { + IInputMethodClient client, IBinder windowToken, int flags, + ResultReceiver resultReceiver) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final int userId = UserHandle.getUserId(callingUid); diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index 63054cf0c516..b4ec359f0466 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -40,7 +40,6 @@ import android.content.integrity.Rule; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.ParceledListSlice; import android.content.pm.Signature; @@ -80,8 +79,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** Implementation of {@link AppIntegrityManagerService}. */ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { @@ -102,12 +103,14 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { private static final String TAG = "AppIntegrityManagerServiceImpl"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; - private static final String PACKAGE_INSTALLER = "com.google.android.packageinstaller"; private static final String BASE_APK_FILE = "base.apk"; private static final String ALLOWED_INSTALLERS_METADATA_NAME = "allowed-installers"; private static final String ALLOWED_INSTALLER_DELIMITER = ","; private static final String INSTALLER_PACKAGE_CERT_DELIMITER = "\\|"; + private static final Set<String> PACKAGE_INSTALLER = new HashSet<>( + Arrays.asList("com.google.android.packageinstaller", "com.android.packageinstaller")); + // Access to files inside mRulesDir is protected by mRulesLock; private final Context mContext; private final Handler mHandler; @@ -115,8 +118,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { private final RuleEvaluationEngine mEvaluationEngine; private final IntegrityFileManager mIntegrityFileManager; - private final boolean mCheckIntegrityForRuleProviders; - /** Create an instance of {@link AppIntegrityManagerServiceImpl}. */ public static AppIntegrityManagerServiceImpl create(Context context) { HandlerThread handlerThread = new HandlerThread("AppIntegrityManagerServiceHandler"); @@ -127,13 +128,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { LocalServices.getService(PackageManagerInternal.class), RuleEvaluationEngine.getRuleEvaluationEngine(), IntegrityFileManager.getInstance(), - handlerThread.getThreadHandler(), - Settings.Global.getInt( - context.getContentResolver(), - Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, - 0) - == 1 - ); + handlerThread.getThreadHandler()); } @VisibleForTesting @@ -142,14 +137,12 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { PackageManagerInternal packageManagerInternal, RuleEvaluationEngine evaluationEngine, IntegrityFileManager integrityFileManager, - Handler handler, - boolean checkIntegrityForRuleProviders) { + Handler handler) { mContext = context; mPackageManagerInternal = packageManagerInternal; mEvaluationEngine = evaluationEngine; mIntegrityFileManager = integrityFileManager; mHandler = handler; - mCheckIntegrityForRuleProviders = checkIntegrityForRuleProviders; IntentFilter integrityVerificationFilter = new IntentFilter(); integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION); @@ -202,7 +195,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { intent, /* onFinished= */ null, /* handler= */ null); - } catch (IntentSender.SendIntentException e) { + } catch (Exception e) { Slog.e(TAG, "Error sending status feedback.", e); } }); @@ -260,7 +253,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { String installerPackageName = getInstallerPackageName(intent); // Skip integrity verification if the verifier is doing the install. - if (!mCheckIntegrityForRuleProviders + if (!integrityCheckIncludesRuleProvider() && isRuleProvider(installerPackageName)) { Slog.i(TAG, "Verifier doing the install. Skipping integrity check."); mPackageManagerInternal.setIntegrityVerificationResult( @@ -272,8 +265,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { List<String> installerCertificates = getInstallerCertificateFingerprint(installerPackageName); - Slog.w(TAG, appCertificates.toString()); - AppInstallMetadata.Builder builder = new AppInstallMetadata.Builder(); builder.setPackageName(getPackageNameNormalized(packageName)); @@ -377,7 +368,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { // A common way for apps to install packages is to send an intent to PackageInstaller. In // that case, the installer will always show up as PackageInstaller which is not what we // want. - if (installer.equals(PACKAGE_INSTALLER)) { + if (PACKAGE_INSTALLER.contains(installer)) { int originatingUid = intent.getIntExtra(EXTRA_ORIGINATING_UID, -1); if (originatingUid < 0) { Slog.e(TAG, "Installer is package installer but originating UID not found."); @@ -632,4 +623,12 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { return getAllowedRuleProviders().stream() .anyMatch(ruleProvider -> ruleProvider.equals(installerPackageName)); } + + private boolean integrityCheckIncludesRuleProvider() { + return Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, + 0) + == 1; + } } diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java index b3546dc79572..a3523f23ddcf 100644 --- a/services/core/java/com/android/server/location/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/GnssConfiguration.java @@ -80,7 +80,7 @@ class GnssConfiguration { // Represents an HAL interface version. Instances of this class are created in the JNI layer // and returned through native methods. - private static class HalInterfaceVersion { + static class HalInterfaceVersion { final int mMajor; final int mMinor; @@ -206,6 +206,10 @@ class GnssConfiguration { native_set_satellite_blacklist(constellations, svids); } + HalInterfaceVersion getHalInterfaceVersion() { + return native_get_gnss_configuration_version(); + } + interface SetCarrierProperty { boolean set(int value); } @@ -232,8 +236,7 @@ class GnssConfiguration { logConfigurations(); - final HalInterfaceVersion gnssConfigurationIfaceVersion = - native_get_gnss_configuration_version(); + final HalInterfaceVersion gnssConfigurationIfaceVersion = getHalInterfaceVersion(); if (gnssConfigurationIfaceVersion != null) { // Set to a range checked value. if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion) diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 5c2bf2632920..58e332ab6d1d 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -807,10 +807,15 @@ public class GnssLocationProvider extends AbstractLocationProvider implements locationRequest.setProvider(provider); - // Ignore location settings if in emergency mode. - if (isUserEmergency && mNIHandler.getInEmergency()) { - locationRequest.setLocationSettingsIgnored(true); - durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER; + // Ignore location settings if in emergency mode. This is only allowed for + // isUserEmergency request (introduced in HAL v2.0), or DBH request in HAL v1.1. + if (mNIHandler.getInEmergency()) { + GnssConfiguration.HalInterfaceVersion halVersion = + mGnssConfiguration.getHalInterfaceVersion(); + if (isUserEmergency || (halVersion.mMajor < 2 && !independentFromGnss)) { + locationRequest.setLocationSettingsIgnored(true); + durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER; + } } Log.i(TAG, diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 15dfab93ed27..6faf67486ff3 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -50,7 +50,6 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DeviceStateCache; import android.app.admin.PasswordMetrics; -import android.app.backup.BackupManager; import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; import android.content.BroadcastReceiver; @@ -112,10 +111,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Preconditions; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; @@ -701,7 +698,7 @@ public class LockSettingsService extends ILockSettings.Stub { // Serial number is never reusued, so we can use it as a distinguisher for user Id reuse. int serialNumber = mUserManager.getUserSerialNumber(userId); - int storedSerialNumber = getIntUnchecked(USER_SERIAL_NUMBER_KEY, -1, userId); + int storedSerialNumber = mStorage.getInt(USER_SERIAL_NUMBER_KEY, -1, userId); if (storedSerialNumber != serialNumber) { // If LockSettingsStorage does not have a copy of the serial number, it could be either // this is a user created before the serial number recording logic is introduced, or @@ -710,7 +707,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (storedSerialNumber != -1) { removeUser(userId, /* unknownUser */ true); } - setIntUnchecked(USER_SERIAL_NUMBER_KEY, serialNumber, userId); + mStorage.setInt(USER_SERIAL_NUMBER_KEY, serialNumber, userId); } } @@ -1069,7 +1066,7 @@ public class LockSettingsService extends ILockSettings.Stub { private boolean getSeparateProfileChallengeEnabledInternal(int userId) { synchronized (mSeparateChallengeLock) { - return getBooleanUnchecked(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId); + return mStorage.getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId); } } @@ -1122,94 +1119,49 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void setBoolean(String key, boolean value, int userId) { checkWritePermission(userId); - setStringUnchecked(key, userId, value ? "1" : "0"); + mStorage.setBoolean(key, value, userId); } @Override public void setLong(String key, long value, int userId) { checkWritePermission(userId); - setLongUnchecked(key, value, userId); - } - - private void setLongUnchecked(String key, long value, int userId) { - setStringUnchecked(key, userId, Long.toString(value)); - } - - private void setIntUnchecked(String key, int value, int userId) { - setStringUnchecked(key, userId, Integer.toString(value)); + mStorage.setLong(key, value, userId); } @Override public void setString(String key, String value, int userId) { checkWritePermission(userId); - setStringUnchecked(key, userId, value); - } - - private void setStringUnchecked(String key, int userId, String value) { - Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user"); - - mStorage.writeKeyValue(key, value, userId); - if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) { - BackupManager.dataChanged("com.android.providers.settings"); - } + mStorage.setString(key, value, userId); } @Override public boolean getBoolean(String key, boolean defaultValue, int userId) { checkReadPermission(key, userId); - return getBooleanUnchecked(key, defaultValue, userId); - } - - private boolean getBooleanUnchecked(String key, boolean defaultValue, int userId) { - String value = getStringUnchecked(key, null, userId); - return TextUtils.isEmpty(value) ? - defaultValue : (value.equals("1") || value.equals("true")); + if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) { + return getCredentialTypeInternal(userId) == CREDENTIAL_TYPE_PATTERN; + } + return mStorage.getBoolean(key, defaultValue, userId); } @Override public long getLong(String key, long defaultValue, int userId) { checkReadPermission(key, userId); - return getLongUnchecked(key, defaultValue, userId); - } - - private long getLongUnchecked(String key, long defaultValue, int userId) { - String value = getStringUnchecked(key, null, userId); - return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value); - } - - private int getIntUnchecked(String key, int defaultValue, int userId) { - String value = getStringUnchecked(key, null, userId); - return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value); + return mStorage.getLong(key, defaultValue, userId); } @Override public String getString(String key, String defaultValue, int userId) { checkReadPermission(key, userId); - return getStringUnchecked(key, defaultValue, userId); - } - - private String getStringUnchecked(String key, String defaultValue, int userId) { - if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) { - return getCredentialTypeInternal(userId) == CREDENTIAL_TYPE_PATTERN ? "1" : "0"; - } - if (userId == USER_FRP) { - return null; - } - - if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) { - key = Settings.Secure.LOCK_PATTERN_ENABLED; - } - - return mStorage.readKeyValue(key, defaultValue, userId); + return mStorage.getString(key, defaultValue, userId); } private void setKeyguardStoredQuality(int quality, int userId) { if (DEBUG) Slog.d(TAG, "setKeyguardStoredQuality: user=" + userId + " quality=" + quality); - setLongUnchecked(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId); + mStorage.setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId); } private int getKeyguardStoredQuality(int userId) { - return (int) getLongUnchecked(LockPatternUtils.PASSWORD_TYPE_KEY, + return (int) mStorage.getLong(LockPatternUtils.PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId); } @@ -2493,13 +2445,6 @@ public class LockSettingsService extends ILockSettings.Stub { SEPARATE_PROFILE_CHALLENGE_KEY }; - private static final String[] SETTINGS_TO_BACKUP = new String[] { - Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, - Secure.LOCK_SCREEN_OWNER_INFO, - Secure.LOCK_PATTERN_VISIBLE, - LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS - }; - private class GateKeeperDiedRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index fec0189377c8..81d07cc11527 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -18,8 +18,12 @@ package com.android.server.locksettings; import static android.content.Context.USER_SERVICE; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; +import static com.android.internal.widget.LockPatternUtils.USER_FRP; + import android.annotation.Nullable; import android.app.admin.DevicePolicyManager; +import android.app.backup.BackupManager; import android.content.ContentValues; import android.content.Context; import android.content.pm.UserInfo; @@ -29,6 +33,8 @@ import android.database.sqlite.SQLiteOpenHelper; import android.os.Environment; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; @@ -87,6 +93,13 @@ class LockSettingsStorage { private static final Object DEFAULT = new Object(); + private static final String[] SETTINGS_TO_BACKUP = new String[] { + Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, + Settings.Secure.LOCK_SCREEN_OWNER_INFO, + Settings.Secure.LOCK_PATTERN_VISIBLE, + LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS + }; + private final DatabaseHelper mOpenHelper; private final Context mContext; private final Cache mCache = new Cache(); @@ -136,10 +149,12 @@ class LockSettingsStorage { mOpenHelper.setCallback(callback); } + @VisibleForTesting(visibility = PACKAGE) public void writeKeyValue(String key, String value, int userId) { writeKeyValue(mOpenHelper.getWritableDatabase(), key, value, userId); } + @VisibleForTesting public void writeKeyValue(SQLiteDatabase db, String key, String value, int userId) { ContentValues cv = new ContentValues(); cv.put(COLUMN_KEY, key); @@ -159,6 +174,7 @@ class LockSettingsStorage { } + @VisibleForTesting public String readKeyValue(String key, String defaultValue, int userId) { int version; synchronized (mCache) { @@ -184,6 +200,28 @@ class LockSettingsStorage { return result == DEFAULT ? defaultValue : (String) result; } + @VisibleForTesting + public void removeKey(String key, int userId) { + removeKey(mOpenHelper.getWritableDatabase(), key, userId); + } + + private void removeKey(SQLiteDatabase db, String key, int userId) { + ContentValues cv = new ContentValues(); + cv.put(COLUMN_KEY, key); + cv.put(COLUMN_USERID, userId); + + db.beginTransaction(); + try { + db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?", + new String[] {key, Integer.toString(userId)}); + db.setTransactionSuccessful(); + mCache.removeKey(key, userId); + } finally { + db.endTransaction(); + } + + } + public void prefetchUser(int userId) { int version; synchronized (mCache) { @@ -537,6 +575,55 @@ class LockSettingsStorage { } } + public void setBoolean(String key, boolean value, int userId) { + setString(key, value ? "1" : "0", userId); + } + + public void setLong(String key, long value, int userId) { + setString(key, Long.toString(value), userId); + } + + public void setInt(String key, int value, int userId) { + setString(key, Integer.toString(value), userId); + } + + public void setString(String key, String value, int userId) { + Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user"); + + writeKeyValue(key, value, userId); + if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) { + BackupManager.dataChanged("com.android.providers.settings"); + } + } + + public boolean getBoolean(String key, boolean defaultValue, int userId) { + String value = getString(key, null, userId); + return TextUtils.isEmpty(value) + ? defaultValue : (value.equals("1") || value.equals("true")); + } + + public long getLong(String key, long defaultValue, int userId) { + String value = getString(key, null, userId); + return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value); + } + + public int getInt(String key, int defaultValue, int userId) { + String value = getString(key, null, userId); + return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value); + } + + public String getString(String key, String defaultValue, int userId) { + if (userId == USER_FRP) { + return null; + } + + if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) { + key = Settings.Secure.LOCK_PATTERN_ENABLED; + } + + return readKeyValue(key, defaultValue, userId); + } + @VisibleForTesting void closeDatabase() { mOpenHelper.close(); @@ -764,6 +851,10 @@ class LockSettingsStorage { putIfUnchanged(CacheKey.TYPE_KEY_VALUE, key, value, userId, version); } + void removeKey(String key, int userId) { + remove(CacheKey.TYPE_KEY_VALUE, key, userId); + } + byte[] peekFile(String fileName) { return copyOf((byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */)); } @@ -788,6 +879,9 @@ class LockSettingsStorage { return contains(CacheKey.TYPE_FETCHED, "", userId); } + private synchronized void remove(int type, String key, int userId) { + mCache.remove(mCacheKey.set(type, key, userId)); + } private synchronized void put(int type, String key, Object value, int userId) { // Create a new CachKey here because it may be saved in the map if the key is absent. diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index c9e356ec1470..351dd6ed3d3d 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -16,6 +16,8 @@ package com.android.server.locksettings; +import static android.os.UserHandle.USER_SYSTEM; + import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; @@ -24,6 +26,7 @@ import android.hardware.rebootescrow.IRebootEscrow; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserManager; +import android.provider.Settings; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -40,6 +43,26 @@ class RebootEscrowManager { private static final String TAG = "RebootEscrowManager"; /** + * Used in the database storage to indicate the boot count at which the reboot escrow was + * previously armed. + */ + @VisibleForTesting + public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count"; + + /** + * Number of boots until we consider the escrow data to be stale for the purposes of metrics. + * <p> + * If the delta between the current boot number and the boot number stored when the mechanism + * was armed is under this number and the escrow mechanism fails, we report it as a failure of + * the mechanism. + * <p> + * If the delta over this number and escrow fails, we will not report the metric as failed + * since there most likely was some other issue if the device rebooted several times before + * getting to the escrow restore code. + */ + private static final int BOOT_COUNT_TOLERANCE = 5; + + /** * Used to track when the reboot escrow is wanted. Should stay true once escrow is requested * unless clearRebootEscrow is called. This will allow all the active users to be unlocked * after reboot. @@ -74,6 +97,7 @@ class RebootEscrowManager { interface Callbacks { boolean isUserSecure(int userId); + void onRebootEscrowRestored(byte spVersion, byte[] syntheticPassword, int userId); } @@ -92,7 +116,8 @@ class RebootEscrowManager { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } - public @Nullable IRebootEscrow getRebootEscrow() { + @Nullable + public IRebootEscrow getRebootEscrow() { try { return IRebootEscrow.Stub.asInterface(ServiceManager.getService( "android.hardware.rebootescrow.IRebootEscrow/default")); @@ -101,6 +126,15 @@ class RebootEscrowManager { } return null; } + + public int getBootCount() { + return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT, + 0); + } + + public void reportMetric(boolean success) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success); + } } RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) { @@ -135,7 +169,7 @@ class RebootEscrowManager { for (UserInfo user : users) { mStorage.removeRebootEscrow(user.id); } - FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, false); + onEscrowRestoreComplete(false); return; } @@ -143,8 +177,19 @@ class RebootEscrowManager { for (UserInfo user : rebootEscrowUsers) { allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey); } - FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, - allUsersUnlocked); + onEscrowRestoreComplete(allUsersUnlocked); + } + + private void onEscrowRestoreComplete(boolean success) { + int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, 0, USER_SYSTEM); + mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); + + int bootCountDelta = mInjector.getBootCount() - previousBootCount; + if (bootCountDelta > BOOT_COUNT_TOLERANCE) { + return; + } + + mInjector.reportMetric(success); } private RebootEscrowKey getAndClearRebootEscrowKey() { @@ -267,6 +312,8 @@ class RebootEscrowManager { return; } + mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); + try { rebootEscrow.storeKey(new byte[32]); } catch (RemoteException e) { @@ -308,6 +355,11 @@ class RebootEscrowManager { } catch (RemoteException e) { Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e); } + + if (armedRebootEscrow) { + mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM); + } + return armedRebootEscrow; } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 9f47b349d3fc..67f9782d1a6d 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -172,7 +172,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR mTag = tag; mSessionInfo = sessionInfo; mController = new ControllerStub(); - mSessionToken = new MediaSession.Token(mController); + mSessionToken = new MediaSession.Token(ownerUid, mController); mSession = new SessionStub(); mSessionCb = new SessionCb(cb); mService = service; diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java index dbaf8241ddd5..377e731fbeeb 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java @@ -84,14 +84,12 @@ public class NotificationHistoryDatabase { // Current version of the database files schema private int mCurrentVersion; private final WriteBufferRunnable mWriteBufferRunnable; - private final FileAttrProvider mFileAttrProvider; // Object containing posted notifications that have not yet been written to disk @VisibleForTesting NotificationHistory mBuffer; - public NotificationHistoryDatabase(Context context, Handler fileWriteHandler, File dir, - FileAttrProvider fileAttrProvider) { + public NotificationHistoryDatabase(Context context, Handler fileWriteHandler, File dir) { mContext = context; mAlarmManager = context.getSystemService(AlarmManager.class); mCurrentVersion = DEFAULT_CURRENT_VERSION; @@ -101,7 +99,6 @@ public class NotificationHistoryDatabase { mHistoryFiles = new LinkedList<>(); mBuffer = new NotificationHistory(); mWriteBufferRunnable = new WriteBufferRunnable(); - mFileAttrProvider = fileAttrProvider; IntentFilter deletionFilter = new IntentFilter(ACTION_HISTORY_DELETION); deletionFilter.addDataScheme(SCHEME_DELETION); @@ -131,8 +128,8 @@ public class NotificationHistoryDatabase { } // Sort with newest files first - Arrays.sort(files, (lhs, rhs) -> Long.compare(mFileAttrProvider.getCreationTime(rhs), - mFileAttrProvider.getCreationTime(lhs))); + Arrays.sort(files, (lhs, rhs) -> Long.compare(Long.parseLong(rhs.getName()), + Long.parseLong(lhs.getName()))); for (File file : files) { mHistoryFiles.addLast(new AtomicFile(file)); @@ -255,10 +252,9 @@ public class NotificationHistoryDatabase { for (int i = mHistoryFiles.size() - 1; i >= 0; i--) { final AtomicFile currentOldestFile = mHistoryFiles.get(i); - final long creationTime = - mFileAttrProvider.getCreationTime(currentOldestFile.getBaseFile()); + final long creationTime = Long.parseLong(currentOldestFile.getBaseFile().getName()); if (DEBUG) { - Slog.d(TAG, "Pruning " + currentOldestFile.getBaseFile().getName() + Slog.d(TAG, "File " + currentOldestFile.getBaseFile().getName() + " created on " + creationTime); } if (creationTime <= retentionBoundary.getTimeInMillis()) { @@ -469,24 +465,4 @@ public class NotificationHistoryDatabase { } } } - - public static final class NotificationHistoryFileAttrProvider implements - NotificationHistoryDatabase.FileAttrProvider { - final static String TAG = "NotifHistoryFileDate"; - - public long getCreationTime(File file) { - try { - BasicFileAttributes attr = Files.readAttributes(FileSystems.getDefault().getPath( - file.getAbsolutePath()), BasicFileAttributes.class); - return attr.creationTime().to(TimeUnit.MILLISECONDS); - } catch (Exception e) { - Slog.w(TAG, "Cannot read creation data for file; using file name"); - return Long.valueOf(file.getName()); - } - } - } - - interface FileAttrProvider { - long getCreationTime(File file); - } } diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabaseFactory.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabaseFactory.java index b4940a5ab647..d9e0d79883c5 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryDatabaseFactory.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabaseFactory.java @@ -31,11 +31,10 @@ public class NotificationHistoryDatabaseFactory { } public static NotificationHistoryDatabase create(@NonNull Context context, - @NonNull Handler handler, @NonNull File rootDir, - @NonNull NotificationHistoryDatabase.FileAttrProvider fileAttrProvider) { + @NonNull Handler handler, @NonNull File rootDir) { if(sTestingNotificationHistoryDb != null) { return sTestingNotificationHistoryDb; } - return new NotificationHistoryDatabase(context, handler, rootDir, fileAttrProvider); + return new NotificationHistoryDatabase(context, handler, rootDir); } } diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java index 88e0dc6e9cc4..ab37f67b3db8 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java @@ -38,7 +38,6 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.IoThread; -import com.android.server.notification.NotificationHistoryDatabase.NotificationHistoryFileAttrProvider; import java.io.File; import java.util.ArrayList; @@ -291,7 +290,7 @@ public class NotificationHistoryManager { final File historyDir = new File(Environment.getDataSystemCeDirectory(userId), DIRECTORY_PER_USER); userHistory = NotificationHistoryDatabaseFactory.create(mContext, IoThread.getHandler(), - historyDir, new NotificationHistoryFileAttrProvider()); + historyDir); if (mUserUnlockedStates.get(userId)) { try { userHistory.init(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 475f229562dd..c40f1b65573d 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -51,6 +51,7 @@ import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.BIND_NOT_PERCEPTIBLE; +import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.PackageManager.FEATURE_LEANBACK; @@ -380,7 +381,7 @@ public class NotificationManagerService extends SystemService { private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2; private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds - private static final long DELAY_FOR_ASSISTANT_TIME = 100; + private static final long DELAY_FOR_ASSISTANT_TIME = 200; private static final String ACTION_NOTIFICATION_TIMEOUT = NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; @@ -569,17 +570,17 @@ public class NotificationManagerService extends SystemService { public StatusBarNotification[] getArray(int count, boolean includeSnoozed) { if (count == 0) count = mBufferSize; - final StatusBarNotification[] a - = new StatusBarNotification[Math.min(count, mBuffer.size())]; + List<StatusBarNotification> a = new ArrayList(); Iterator<Pair<StatusBarNotification, Integer>> iter = descendingIterator(); int i=0; while (iter.hasNext() && i < count) { Pair<StatusBarNotification, Integer> pair = iter.next(); if (pair.second != REASON_SNOOZED || includeSnoozed) { - a[i++] = pair.first; + i++; + a.add(pair.first); } } - return a; + return a.toArray(new StatusBarNotification[a.size()]); } } @@ -2067,19 +2068,16 @@ public class NotificationManagerService extends SystemService { @Override public void onStart() { - SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() { - @Override - public void repost(int userId, NotificationRecord r) { - try { - if (DBG) { - Slog.d(TAG, "Reposting " + r.getKey()); - } - enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(), - r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(), - r.getSbn().getId(), r.getSbn().getNotification(), userId); - } catch (Exception e) { - Slog.e(TAG, "Cannot un-snooze notification", e); + SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> { + try { + if (DBG) { + Slog.d(TAG, "Reposting " + r.getKey()); } + enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(), + r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(), + r.getSbn().getId(), r.getSbn().getNotification(), userId, true); + } catch (Exception e) { + Slog.e(TAG, "Cannot un-snooze notification", e); } }, mUserProfiles); @@ -2699,8 +2697,13 @@ public class NotificationManagerService extends SystemService { CharSequence title = null; if (n.extras != null) { title = n.extras.getCharSequence(Notification.EXTRA_TITLE); + if (title == null) { + title = n.extras.getCharSequence(Notification.EXTRA_TITLE_BIG); + } } - return title == null? null : String.valueOf(title); + return title == null ? getContext().getResources().getString( + com.android.internal.R.string.notification_history_title_placeholder) + : String.valueOf(title); } /** @@ -3448,16 +3451,10 @@ public class NotificationManagerService extends SystemService { ArrayList<ConversationChannelWrapper> conversations = mPreferencesHelper.getConversations(onlyImportant); for (ConversationChannelWrapper conversation : conversations) { - LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() - .setPackage(conversation.getPkg()) - .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) - .setShortcutIds(Arrays.asList( - conversation.getNotificationChannel().getConversationId())); - List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts( - query, UserHandle.of(UserHandle.getUserId(conversation.getUid()))); - if (shortcuts != null && !shortcuts.isEmpty()) { - conversation.setShortcutInfo(shortcuts.get(0)); - } + conversation.setShortcutInfo(getShortcutInfo( + conversation.getNotificationChannel().getConversationId(), + conversation.getPkg(), + UserHandle.of(UserHandle.getUserId(conversation.getUid())))); } return new ParceledListSlice<>(conversations); } @@ -3477,16 +3474,10 @@ public class NotificationManagerService extends SystemService { ArrayList<ConversationChannelWrapper> conversations = mPreferencesHelper.getConversations(pkg, uid); for (ConversationChannelWrapper conversation : conversations) { - LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() - .setPackage(pkg) - .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) - .setShortcutIds(Arrays.asList( - conversation.getNotificationChannel().getConversationId())); - List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts( - query, UserHandle.of(UserHandle.getUserId(uid))); - if (shortcuts != null && !shortcuts.isEmpty()) { - conversation.setShortcutInfo(shortcuts.get(0)); - } + conversation.setShortcutInfo(getShortcutInfo( + conversation.getNotificationChannel().getConversationId(), + pkg, + UserHandle.of(UserHandle.getUserId(uid)))); } return new ParceledListSlice<>(conversations); } @@ -3994,7 +3985,7 @@ public class NotificationManagerService extends SystemService { synchronized (mNotificationLock) { final ManagedServiceInfo info = mAssistants.checkServiceTokenLocked(token); - unsnoozeNotificationInt(key, info); + unsnoozeNotificationInt(key, info, false); } } finally { Binder.restoreCallingIdentity(identity); @@ -4017,7 +4008,7 @@ public class NotificationManagerService extends SystemService { if (!info.isSystem) { throw new SecurityException("Not allowed to unsnooze before deadline"); } - unsnoozeNotificationInt(key, info); + unsnoozeNotificationInt(key, info, true); } } finally { Binder.restoreCallingIdentity(identity); @@ -5536,6 +5527,13 @@ public class NotificationManagerService extends SystemService { void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int incomingUserId) { + enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, + incomingUserId, false); + } + + void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, + final int callingPid, final String tag, final int id, final Notification notification, + int incomingUserId, boolean postSilently) { if (DBG) { Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); @@ -5616,6 +5614,7 @@ public class NotificationManagerService extends SystemService { user, null, System.currentTimeMillis()); final NotificationRecord r = new NotificationRecord(getContext(), n, channel); r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid)); + r.setPostSilently(postSilently); if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { final boolean fgServiceShown = channel.isFgServiceShown(); @@ -5646,6 +5645,8 @@ public class NotificationManagerService extends SystemService { } } + r.setShortcutInfo(getShortcutInfo(notification.getShortcutId(), pkg, user)); + if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, r.getSbn().getOverrideGroupKey() != null)) { return; @@ -5959,20 +5960,33 @@ public class NotificationManagerService extends SystemService { return false; } - private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) { - LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); - if (packageName != null) { - query.setPackage(packageName); - } - if (shortcutId != null) { - query.setShortcutIds(Arrays.asList(shortcutId)); + private ShortcutInfo getShortcutInfo(String shortcutId, String packageName, UserHandle user) { + final long token = Binder.clearCallingIdentity(); + try { + if (shortcutId == null || packageName == null || user == null) { + return null; + } + LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); + if (packageName != null) { + query.setPackage(packageName); + } + if (shortcutId != null) { + query.setShortcutIds(Arrays.asList(shortcutId)); + } + query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED); + List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user); + ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0 + ? shortcuts.get(0) + : null; + return shortcutInfo; + } finally { + Binder.restoreCallingIdentity(token); } - query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED); - List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user); - ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0 - ? shortcuts.get(0) - : null; - return shortcutInfo != null; + } + + private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) { + ShortcutInfo shortcutInfo = getShortcutInfo(shortcutId, packageName, user); + return shortcutInfo != null && shortcutInfo.isLongLived(); } private void logBubbleError(String key, String failureMessage) { @@ -7036,6 +7050,11 @@ public class NotificationManagerService extends SystemService { return true; } + // Suppressed because a user manually unsnoozed something (or similar) + if (record.shouldPostSilently()) { + return true; + } + // muted by listener final String disableEffects = disableNotificationEffects(record); if (disableEffects != null) { @@ -8050,13 +8069,12 @@ public class NotificationManagerService extends SystemService { mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId)); } - void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) { + void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) { String listenerName = listener == null ? null : listener.component.toShortString(); if (DBG) { Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); } - mSnoozeHelper.cleanupPersistedContext(key); - mSnoozeHelper.repost(key); + mSnoozeHelper.repost(key, muteOnReturn); handleSavePolicyFile(); } @@ -8571,7 +8589,8 @@ public class NotificationManagerService extends SystemService { record.getSmartReplies(), record.canBubble(), record.isInterruptive(), - record.isConversation() + record.isConversation(), + record.getShortcutInfo() ); rankings.add(ranking); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index f92e1fcddcf2..3f24b38161c3 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -35,6 +35,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.media.AudioAttributes; import android.media.AudioSystem; @@ -166,6 +167,7 @@ public final class NotificationRecord { private boolean mAllowBubble; private Light mLight; private boolean mIsNotConversationOverride; + private ShortcutInfo mShortcutInfo; /** * This list contains system generated smart actions from NAS, app-generated smart actions are * stored in Notification.actions with isContextual() set to true. @@ -185,6 +187,7 @@ public final class NotificationRecord { private boolean mSuggestionsGeneratedByAssistant; private boolean mEditChoicesBeforeSending; private boolean mHasSeenSmartReplies; + private boolean mPostSilently; /** * Whether this notification (and its channels) should be considered user locked. Used in * conjunction with user sentiment calculation. @@ -854,6 +857,17 @@ public final class NotificationRecord { return mHidden; } + /** + * Override of all alerting information on the channel and notification. Used when notifications + * are reposted in response to direct user action and thus don't need to alert. + */ + public void setPostSilently(boolean postSilently) { + mPostSilently = postSilently; + } + + public boolean shouldPostSilently() { + return mPostSilently; + } public void setSuppressedVisualEffects(int effects) { mSuppressedVisualEffects = effects; @@ -1338,14 +1352,24 @@ public final class NotificationRecord { return hasCustomRemoteView && !hasDecoratedStyle; } - /** Whether this notification is a conversation notification. */ + public void setShortcutInfo(ShortcutInfo shortcutInfo) { + mShortcutInfo = shortcutInfo; + } + + public ShortcutInfo getShortcutInfo() { + return mShortcutInfo; + } + + /** + * Whether this notification is a conversation notification. + */ public boolean isConversation() { Notification notification = getNotification(); if (mChannel.isDemoted() || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) { return false; } - if (notification.getShortcutId() == null + if (mShortcutInfo == null && !FeatureFlagUtils.isEnabled( mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) { return false; @@ -1353,7 +1377,6 @@ public final class NotificationRecord { if (mIsNotConversationOverride) { return false; } - // STOPSHIP b/137397357: Check shortcut to make a further decision return true; } diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index d60c29119c18..9a9e733cb390 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -106,6 +106,8 @@ public class SnoozeHelper { private ArrayMap<String, Integer> mUsers = new ArrayMap<>(); private Callback mCallback; + private final Object mLock = new Object(); + public SnoozeHelper(Context context, Callback callback, ManagedServices.UserProfiles userProfiles) { mContext = context; @@ -122,41 +124,52 @@ public class SnoozeHelper { } void cleanupPersistedContext(String key){ - int userId = mUsers.get(key); - String pkg = mPackages.get(key); - synchronized (mPersistedSnoozedNotificationsWithContext) { - removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext); + synchronized (mLock) { + int userId = mUsers.get(key); + String pkg = mPackages.get(key); + removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotificationsWithContext); } } - //This function has a side effect of removing the time from the list of persisted notifications. - //IT IS NOT IDEMPOTENT! @NonNull protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) { - Long time; - synchronized (mPersistedSnoozedNotifications) { - time = removeRecord(pkg, key, userId, mPersistedSnoozedNotifications); + Long time = null; + synchronized (mLock) { + ArrayMap<String, Long> snoozed = + mPersistedSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (snoozed != null) { + time = snoozed.get(key); + } } if (time == null) { - return 0L; + time = 0L; } return time; } protected String getSnoozeContextForUnpostedNotification(int userId, String pkg, String key) { - synchronized (mPersistedSnoozedNotificationsWithContext) { - return removeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext); + synchronized (mLock) { + ArrayMap<String, String> snoozed = + mPersistedSnoozedNotificationsWithContext.get(getPkgKey(userId, pkg)); + if (snoozed != null) { + return snoozed.get(key); + } } + return null; } protected boolean isSnoozed(int userId, String pkg, String key) { - return mSnoozedNotifications.containsKey(getPkgKey(userId, pkg)) - && mSnoozedNotifications.get(getPkgKey(userId, pkg)).containsKey(key); + synchronized (mLock) { + return mSnoozedNotifications.containsKey(getPkgKey(userId, pkg)) + && mSnoozedNotifications.get(getPkgKey(userId, pkg)).containsKey(key); + } } protected Collection<NotificationRecord> getSnoozed(int userId, String pkg) { - if (mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))) { - return mSnoozedNotifications.get(getPkgKey(userId, pkg)).values(); + synchronized (mLock) { + if (mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))) { + return mSnoozedNotifications.get(getPkgKey(userId, pkg)).values(); + } } return Collections.EMPTY_LIST; } @@ -165,14 +178,16 @@ public class SnoozeHelper { ArrayList<NotificationRecord> getNotifications(String pkg, String groupKey, Integer userId) { ArrayList<NotificationRecord> records = new ArrayList<>(); - ArrayMap<String, NotificationRecord> allRecords = - mSnoozedNotifications.get(getPkgKey(userId, pkg)); - if (allRecords != null) { - for (int i = 0; i < allRecords.size(); i++) { - NotificationRecord r = allRecords.valueAt(i); - String currentGroupKey = r.getSbn().getGroup(); - if (Objects.equals(currentGroupKey, groupKey)) { - records.add(r); + synchronized (mLock) { + ArrayMap<String, NotificationRecord> allRecords = + mSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (allRecords != null) { + for (int i = 0; i < allRecords.size(); i++) { + NotificationRecord r = allRecords.valueAt(i); + String currentGroupKey = r.getSbn().getGroup(); + if (Objects.equals(currentGroupKey, groupKey)) { + records.add(r); + } } } } @@ -180,30 +195,34 @@ public class SnoozeHelper { } protected NotificationRecord getNotification(String key) { - if (!mUsers.containsKey(key) || !mPackages.containsKey(key)) { - Slog.w(TAG, "Snoozed data sets no longer agree for " + key); - return null; - } - int userId = mUsers.get(key); - String pkg = mPackages.get(key); - ArrayMap<String, NotificationRecord> snoozed = - mSnoozedNotifications.get(getPkgKey(userId, pkg)); - if (snoozed == null) { - return null; + synchronized (mLock) { + if (!mUsers.containsKey(key) || !mPackages.containsKey(key)) { + Slog.w(TAG, "Snoozed data sets no longer agree for " + key); + return null; + } + int userId = mUsers.get(key); + String pkg = mPackages.get(key); + ArrayMap<String, NotificationRecord> snoozed = + mSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (snoozed == null) { + return null; + } + return snoozed.get(key); } - return snoozed.get(key); } protected @NonNull List<NotificationRecord> getSnoozed() { - // caller filters records based on the current user profiles and listener access, so just - // return everything - List<NotificationRecord> snoozed= new ArrayList<>(); - for (String userPkgKey : mSnoozedNotifications.keySet()) { - ArrayMap<String, NotificationRecord> snoozedRecords = - mSnoozedNotifications.get(userPkgKey); - snoozed.addAll(snoozedRecords.values()); + synchronized (mLock) { + // caller filters records based on the current user profiles and listener access, so just + // return everything + List<NotificationRecord> snoozed = new ArrayList<>(); + for (String userPkgKey : mSnoozedNotifications.keySet()) { + ArrayMap<String, NotificationRecord> snoozedRecords = + mSnoozedNotifications.get(userPkgKey); + snoozed.addAll(snoozedRecords.values()); + } + return snoozed; } - return snoozed; } /** @@ -216,9 +235,9 @@ public class SnoozeHelper { snooze(record); scheduleRepost(pkg, key, userId, duration); - Long activateAt = SystemClock.elapsedRealtime() + duration; - synchronized (mPersistedSnoozedNotifications) { - storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, activateAt); + Long activateAt = System.currentTimeMillis() + duration; + synchronized (mLock) { + storeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications, activateAt); } } @@ -228,8 +247,8 @@ public class SnoozeHelper { protected void snooze(NotificationRecord record, String contextId) { int userId = record.getUser().getIdentifier(); if (contextId != null) { - synchronized (mPersistedSnoozedNotificationsWithContext) { - storeRecord(record.getSbn().getPackageName(), record.getKey(), + synchronized (mLock) { + storeRecordLocked(record.getSbn().getPackageName(), record.getKey(), userId, mPersistedSnoozedNotificationsWithContext, contextId); } } @@ -241,25 +260,26 @@ public class SnoozeHelper { if (DEBUG) { Slog.d(TAG, "Snoozing " + record.getKey()); } - storeRecord(record.getSbn().getPackageName(), record.getKey(), - userId, mSnoozedNotifications, record); + synchronized (mLock) { + storeRecordLocked(record.getSbn().getPackageName(), record.getKey(), + userId, mSnoozedNotifications, record); + } } - private <T> void storeRecord(String pkg, String key, Integer userId, + private <T> void storeRecordLocked(String pkg, String key, Integer userId, ArrayMap<String, ArrayMap<String, T>> targets, T object) { + mPackages.put(key, pkg); + mUsers.put(key, userId); ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg)); if (keyToValue == null) { keyToValue = new ArrayMap<>(); } keyToValue.put(key, object); targets.put(getPkgKey(userId, pkg), keyToValue); - - mPackages.put(key, pkg); - mUsers.put(key, userId); } - private <T> T removeRecord(String pkg, String key, Integer userId, + private <T> T removeRecordLocked(String pkg, String key, Integer userId, ArrayMap<String, ArrayMap<String, T>> targets) { T object = null; ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg)); @@ -274,15 +294,17 @@ public class SnoozeHelper { } protected boolean cancel(int userId, String pkg, String tag, int id) { - ArrayMap<String, NotificationRecord> recordsForPkg = - mSnoozedNotifications.get(getPkgKey(userId, pkg)); - if (recordsForPkg != null) { - final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet(); - for (Map.Entry<String, NotificationRecord> record : records) { - final StatusBarNotification sbn = record.getValue().getSbn(); - if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) { - record.getValue().isCanceled = true; - return true; + synchronized (mLock) { + ArrayMap<String, NotificationRecord> recordsForPkg = + mSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (recordsForPkg != null) { + final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet(); + for (Map.Entry<String, NotificationRecord> record : records) { + final StatusBarNotification sbn = record.getValue().getSbn(); + if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) { + record.getValue().isCanceled = true; + return true; + } } } } @@ -290,125 +312,149 @@ public class SnoozeHelper { } protected void cancel(int userId, boolean includeCurrentProfiles) { - if (mSnoozedNotifications.size() == 0) { - return; - } - IntArray userIds = new IntArray(); - userIds.add(userId); - if (includeCurrentProfiles) { - userIds = mUserProfiles.getCurrentProfileIds(); - } - for (ArrayMap<String, NotificationRecord> snoozedRecords : mSnoozedNotifications.values()) { - for (NotificationRecord r : snoozedRecords.values()) { - if (userIds.binarySearch(r.getUserId()) >= 0) { - r.isCanceled = true; + synchronized (mLock) { + if (mSnoozedNotifications.size() == 0) { + return; + } + IntArray userIds = new IntArray(); + userIds.add(userId); + if (includeCurrentProfiles) { + userIds = mUserProfiles.getCurrentProfileIds(); + } + for (ArrayMap<String, NotificationRecord> snoozedRecords : mSnoozedNotifications.values()) { + for (NotificationRecord r : snoozedRecords.values()) { + if (userIds.binarySearch(r.getUserId()) >= 0) { + r.isCanceled = true; + } } } } } protected boolean cancel(int userId, String pkg) { - ArrayMap<String, NotificationRecord> records = - mSnoozedNotifications.get(getPkgKey(userId, pkg)); - if (records == null) { - return false; - } - int N = records.size(); - for (int i = 0; i < N; i++) { - records.valueAt(i).isCanceled = true; + synchronized (mLock) { + ArrayMap<String, NotificationRecord> records = + mSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (records == null) { + return false; + } + int N = records.size(); + for (int i = 0; i < N; i++) { + records.valueAt(i).isCanceled = true; + } + return true; } - return true; } /** * Updates the notification record so the most up to date information is shown on re-post. */ protected void update(int userId, NotificationRecord record) { - ArrayMap<String, NotificationRecord> records = - mSnoozedNotifications.get(getPkgKey(userId, record.getSbn().getPackageName())); - if (records == null) { - return; + synchronized (mLock) { + ArrayMap<String, NotificationRecord> records = + mSnoozedNotifications.get(getPkgKey(userId, record.getSbn().getPackageName())); + if (records == null) { + return; + } + records.put(record.getKey(), record); } - records.put(record.getKey(), record); } - protected void repost(String key) { - Integer userId = mUsers.get(key); - if (userId != null) { - repost(key, userId); + protected void repost(String key, boolean muteOnReturn) { + synchronized (mLock) { + Integer userId = mUsers.get(key); + if (userId != null) { + repost(key, userId, muteOnReturn); + } } } - protected void repost(String key, int userId) { - final String pkg = mPackages.remove(key); - ArrayMap<String, NotificationRecord> records = - mSnoozedNotifications.get(getPkgKey(userId, pkg)); - if (records == null) { - return; + protected void repost(String key, int userId, boolean muteOnReturn) { + NotificationRecord record; + synchronized (mLock) { + final String pkg = mPackages.remove(key); + mUsers.remove(key); + removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications); + removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotificationsWithContext); + ArrayMap<String, NotificationRecord> records = + mSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (records == null) { + return; + } + record = records.remove(key); + } - final NotificationRecord record = records.remove(key); - mPackages.remove(key); - mUsers.remove(key); if (record != null && !record.isCanceled) { - final PendingIntent pi = createPendingIntent(pkg, record.getKey(), userId); + final PendingIntent pi = createPendingIntent( + record.getSbn().getPackageName(), record.getKey(), userId); mAm.cancel(pi); MetricsLogger.action(record.getLogMaker() .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) .setType(MetricsProto.MetricsEvent.TYPE_OPEN)); - mCallback.repost(userId, record); + mCallback.repost(userId, record, muteOnReturn); } } protected void repostGroupSummary(String pkg, int userId, String groupKey) { - ArrayMap<String, NotificationRecord> recordsByKey - = mSnoozedNotifications.get(getPkgKey(userId, pkg)); - if (recordsByKey == null) { - return; - } - - String groupSummaryKey = null; - int N = recordsByKey.size(); - for (int i = 0; i < N; i++) { - final NotificationRecord potentialGroupSummary = recordsByKey.valueAt(i); - if (potentialGroupSummary.getSbn().isGroup() - && potentialGroupSummary.getNotification().isGroupSummary() - && groupKey.equals(potentialGroupSummary.getGroupKey())) { - groupSummaryKey = potentialGroupSummary.getKey(); - break; + synchronized (mLock) { + ArrayMap<String, NotificationRecord> recordsByKey + = mSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (recordsByKey == null) { + return; } - } - if (groupSummaryKey != null) { - NotificationRecord record = recordsByKey.remove(groupSummaryKey); - mPackages.remove(groupSummaryKey); - mUsers.remove(groupSummaryKey); + String groupSummaryKey = null; + int N = recordsByKey.size(); + for (int i = 0; i < N; i++) { + final NotificationRecord potentialGroupSummary = recordsByKey.valueAt(i); + if (potentialGroupSummary.getSbn().isGroup() + && potentialGroupSummary.getNotification().isGroupSummary() + && groupKey.equals(potentialGroupSummary.getGroupKey())) { + groupSummaryKey = potentialGroupSummary.getKey(); + break; + } + } - if (record != null && !record.isCanceled) { - MetricsLogger.action(record.getLogMaker() - .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) - .setType(MetricsProto.MetricsEvent.TYPE_OPEN)); - mCallback.repost(userId, record); + if (groupSummaryKey != null) { + NotificationRecord record = recordsByKey.remove(groupSummaryKey); + mPackages.remove(groupSummaryKey); + mUsers.remove(groupSummaryKey); + + if (record != null && !record.isCanceled) { + Runnable runnable = () -> { + MetricsLogger.action(record.getLogMaker() + .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) + .setType(MetricsProto.MetricsEvent.TYPE_OPEN)); + mCallback.repost(userId, record, false); + }; + runnable.run(); + } } } } protected void clearData(int userId, String pkg) { - ArrayMap<String, NotificationRecord> records = - mSnoozedNotifications.get(getPkgKey(userId, pkg)); - if (records == null) { - return; - } - for (int i = records.size() - 1; i >= 0; i--) { - final NotificationRecord r = records.removeAt(i); - if (r != null) { - mPackages.remove(r.getKey()); - mUsers.remove(r.getKey()); - final PendingIntent pi = createPendingIntent(pkg, r.getKey(), userId); - mAm.cancel(pi); - MetricsLogger.action(r.getLogMaker() - .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) - .setType(MetricsProto.MetricsEvent.TYPE_DISMISS)); + synchronized (mLock) { + ArrayMap<String, NotificationRecord> records = + mSnoozedNotifications.get(getPkgKey(userId, pkg)); + if (records == null) { + return; + } + for (int i = records.size() - 1; i >= 0; i--) { + final NotificationRecord r = records.removeAt(i); + if (r != null) { + mPackages.remove(r.getKey()); + mUsers.remove(r.getKey()); + Runnable runnable = () -> { + final PendingIntent pi = createPendingIntent(pkg, r.getKey(), userId); + mAm.cancel(pi); + MetricsLogger.action(r.getLogMaker() + .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) + .setType(MetricsProto.MetricsEvent.TYPE_DISMISS)); + }; + runnable.run(); + } } } } @@ -425,93 +471,102 @@ public class SnoozeHelper { } public void scheduleRepostsForPersistedNotifications(long currentTime) { - for (ArrayMap<String, Long> snoozed : mPersistedSnoozedNotifications.values()) { - for (int i = 0; i < snoozed.size(); i++) { - String key = snoozed.keyAt(i); - Long time = snoozed.valueAt(i); - String pkg = mPackages.get(key); - Integer userId = mUsers.get(key); - if (time == null || pkg == null || userId == null) { - Slog.w(TAG, "data out of sync: " + time + "|" + pkg + "|" + userId); - continue; - } - if (time != null && time > currentTime) { - scheduleRepostAtTime(pkg, key, userId, time); + synchronized (mLock) { + for (ArrayMap<String, Long> snoozed : mPersistedSnoozedNotifications.values()) { + for (int i = 0; i < snoozed.size(); i++) { + String key = snoozed.keyAt(i); + Long time = snoozed.valueAt(i); + String pkg = mPackages.get(key); + Integer userId = mUsers.get(key); + if (time == null || pkg == null || userId == null) { + Slog.w(TAG, "data out of sync: " + time + "|" + pkg + "|" + userId); + continue; + } + if (time != null && time > currentTime) { + scheduleRepostAtTime(pkg, key, userId, time); + } } } - } } private void scheduleRepost(String pkg, String key, int userId, long duration) { - scheduleRepostAtTime(pkg, key, userId, SystemClock.elapsedRealtime() + duration); + scheduleRepostAtTime(pkg, key, userId, System.currentTimeMillis() + duration); } private void scheduleRepostAtTime(String pkg, String key, int userId, long time) { - long identity = Binder.clearCallingIdentity(); - try { - final PendingIntent pi = createPendingIntent(pkg, key, userId); - mAm.cancel(pi); - if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time)); - mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi); - } finally { - Binder.restoreCallingIdentity(identity); - } + Runnable runnable = () -> { + long identity = Binder.clearCallingIdentity(); + try { + final PendingIntent pi = createPendingIntent(pkg, key, userId); + mAm.cancel(pi); + if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time)); + mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi); + } finally { + Binder.restoreCallingIdentity(identity); + } + }; + runnable.run(); } public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) { - pw.println("\n Snoozed notifications:"); - for (String userPkgKey : mSnoozedNotifications.keySet()) { - pw.print(INDENT); - pw.println("key: " + userPkgKey); - ArrayMap<String, NotificationRecord> snoozedRecords = - mSnoozedNotifications.get(userPkgKey); - Set<String> snoozedKeys = snoozedRecords.keySet(); - for (String key : snoozedKeys) { - pw.print(INDENT); + synchronized (mLock) { + pw.println("\n Snoozed notifications:"); + for (String userPkgKey : mSnoozedNotifications.keySet()) { pw.print(INDENT); - pw.print(INDENT); - pw.println(key); - } - } - pw.println("\n Pending snoozed notifications"); - for (String userPkgKey : mPersistedSnoozedNotifications.keySet()) { - pw.print(INDENT); - pw.println("key: " + userPkgKey); - ArrayMap<String, Long> snoozedRecords = - mPersistedSnoozedNotifications.get(userPkgKey); - if (snoozedRecords == null) { - continue; + pw.println("key: " + userPkgKey); + ArrayMap<String, NotificationRecord> snoozedRecords = + mSnoozedNotifications.get(userPkgKey); + Set<String> snoozedKeys = snoozedRecords.keySet(); + for (String key : snoozedKeys) { + pw.print(INDENT); + pw.print(INDENT); + pw.print(INDENT); + pw.println(key); + } } - Set<String> snoozedKeys = snoozedRecords.keySet(); - for (String key : snoozedKeys) { - pw.print(INDENT); - pw.print(INDENT); - pw.print(INDENT); - pw.print(key); + pw.println("\n Pending snoozed notifications"); + for (String userPkgKey : mPersistedSnoozedNotifications.keySet()) { pw.print(INDENT); - pw.println(snoozedRecords.get(key)); + pw.println("key: " + userPkgKey); + ArrayMap<String, Long> snoozedRecords = + mPersistedSnoozedNotifications.get(userPkgKey); + if (snoozedRecords == null) { + continue; + } + Set<String> snoozedKeys = snoozedRecords.keySet(); + for (String key : snoozedKeys) { + pw.print(INDENT); + pw.print(INDENT); + pw.print(INDENT); + pw.print(key); + pw.print(INDENT); + pw.println(snoozedRecords.get(key)); + } } } } protected void writeXml(XmlSerializer out) throws IOException { - final long currentTime = System.currentTimeMillis(); - out.startTag(null, XML_TAG_NAME); - writeXml(out, mPersistedSnoozedNotifications, XML_SNOOZED_NOTIFICATION, - value -> { - if (value < currentTime) { - return; - } - out.attribute(null, XML_SNOOZED_NOTIFICATION_TIME, - value.toString()); - }); - writeXml(out, mPersistedSnoozedNotificationsWithContext, XML_SNOOZED_NOTIFICATION_CONTEXT, - value -> { - out.attribute(null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID, - value); - }); - out.endTag(null, XML_TAG_NAME); + synchronized (mLock) { + final long currentTime = System.currentTimeMillis(); + out.startTag(null, XML_TAG_NAME); + writeXml(out, mPersistedSnoozedNotifications, XML_SNOOZED_NOTIFICATION, + value -> { + if (value < currentTime) { + return; + } + out.attribute(null, XML_SNOOZED_NOTIFICATION_TIME, + value.toString()); + }); + writeXml(out, mPersistedSnoozedNotificationsWithContext, + XML_SNOOZED_NOTIFICATION_CONTEXT, + value -> { + out.attribute(null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID, + value); + }); + out.endTag(null, XML_TAG_NAME); + } } private interface Inserter<T> { @@ -522,32 +577,35 @@ public class SnoozeHelper { ArrayMap<String, ArrayMap<String, T>> targets, String tag, Inserter<T> attributeInserter) throws IOException { - synchronized (targets) { - final int M = targets.size(); - for (int i = 0; i < M; i++) { - // T is a String (snoozed until context) or Long (snoozed until time) - ArrayMap<String, T> keyToValue = targets.valueAt(i); - for (int j = 0; j < keyToValue.size(); j++) { - String key = keyToValue.keyAt(j); - T value = keyToValue.valueAt(j); - String pkg = mPackages.get(key); - Integer userId = mUsers.get(key); + final int M = targets.size(); + for (int i = 0; i < M; i++) { + // T is a String (snoozed until context) or Long (snoozed until time) + ArrayMap<String, T> keyToValue = targets.valueAt(i); + for (int j = 0; j < keyToValue.size(); j++) { + String key = keyToValue.keyAt(j); + T value = keyToValue.valueAt(j); + String pkg = mPackages.get(key); + Integer userId = mUsers.get(key); - out.startTag(null, tag); + if (pkg == null || userId == null) { + Slog.w(TAG, "pkg " + pkg + " or user " + userId + " missing for " + key); + continue; + } - attributeInserter.insert(value); + out.startTag(null, tag); - out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL, - XML_SNOOZED_NOTIFICATION_VERSION); - out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key); + attributeInserter.insert(value); + out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL, + XML_SNOOZED_NOTIFICATION_VERSION); + out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key); - out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg); - out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID, - String.valueOf(userId)); - out.endTag(null, tag); - } + out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg); + out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID, + String.valueOf(userId)); + + out.endTag(null, tag); } } } @@ -575,16 +633,18 @@ public class SnoozeHelper { final Long time = XmlUtils.readLongAttribute( parser, XML_SNOOZED_NOTIFICATION_TIME, 0); if (time > currentTime) { //only read new stuff - synchronized (mPersistedSnoozedNotifications) { - storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, time); + synchronized (mLock) { + storeRecordLocked( + pkg, key, userId, mPersistedSnoozedNotifications, time); } } } if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) { final String creationId = parser.getAttributeValue( null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID); - synchronized (mPersistedSnoozedNotificationsWithContext) { - storeRecord(pkg, key, userId, mPersistedSnoozedNotificationsWithContext, + synchronized (mLock) { + storeRecordLocked( + pkg, key, userId, mPersistedSnoozedNotificationsWithContext, creationId); } } @@ -601,7 +661,7 @@ public class SnoozeHelper { } protected interface Callback { - void repost(int userId, NotificationRecord r); + void repost(int userId, NotificationRecord r, boolean muteOnReturn); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -612,7 +672,7 @@ public class SnoozeHelper { } if (REPOST_ACTION.equals(intent.getAction())) { repost(intent.getStringExtra(EXTRA_KEY), intent.getIntExtra(EXTRA_USER_ID, - UserHandle.USER_SYSTEM)); + UserHandle.USER_SYSTEM), false); } } }; diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index f3c912817d05..7c9be2dfacd6 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -21,17 +21,17 @@ import static com.android.server.om.OverlayManagerService.TAG; import android.annotation.NonNull; import android.content.om.OverlayInfo; +import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.os.Build.VERSION_CODES; -import android.os.IIdmap2; +import android.os.OverlayablePolicy; import android.os.SystemProperties; import android.os.UserHandle; import android.util.Slog; -import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper; - import java.io.File; +import java.io.IOException; /** * Handle the creation and deletion of idmap files. @@ -55,11 +55,11 @@ class IdmapManager { VENDOR_IS_Q_OR_LATER = isQOrLater; } - private final PackageManagerHelper mPackageManager; + private final OverlayableInfoCallback mOverlayableCallback; private final IdmapDaemon mIdmapDaemon; - IdmapManager(final PackageManagerHelper packageManager) { - mPackageManager = packageManager; + IdmapManager(final OverlayableInfoCallback verifyCallback) { + mOverlayableCallback = verifyCallback; mIdmapDaemon = IdmapDaemon.getInstance(); } @@ -148,40 +148,67 @@ class IdmapManager { private int calculateFulfilledPolicies(@NonNull final PackageInfo targetPackage, @NonNull final PackageInfo overlayPackage, int userId) { final ApplicationInfo ai = overlayPackage.applicationInfo; - int fulfilledPolicies = IIdmap2.POLICY_PUBLIC; + int fulfilledPolicies = OverlayablePolicy.PUBLIC; // Overlay matches target signature - if (mPackageManager.signaturesMatching(targetPackage.packageName, + if (mOverlayableCallback.signaturesMatching(targetPackage.packageName, overlayPackage.packageName, userId)) { - fulfilledPolicies |= IIdmap2.POLICY_SIGNATURE; + fulfilledPolicies |= OverlayablePolicy.SIGNATURE; + } + + // Overlay matches actor signature + if (matchesActorSignature(targetPackage, overlayPackage, userId)) { + fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE; } // Vendor partition (/vendor) if (ai.isVendor()) { - return fulfilledPolicies | IIdmap2.POLICY_VENDOR_PARTITION; + return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION; } // Product partition (/product) if (ai.isProduct()) { - return fulfilledPolicies | IIdmap2.POLICY_PRODUCT_PARTITION; + return fulfilledPolicies | OverlayablePolicy.PRODUCT_PARTITION; } // Odm partition (/odm) if (ai.isOdm()) { - return fulfilledPolicies | IIdmap2.POLICY_ODM_PARTITION; + return fulfilledPolicies | OverlayablePolicy.ODM_PARTITION; } // Oem partition (/oem) if (ai.isOem()) { - return fulfilledPolicies | IIdmap2.POLICY_OEM_PARTITION; + return fulfilledPolicies | OverlayablePolicy.OEM_PARTITION; } // System_ext partition (/system_ext) is considered as system // Check this last since every partition except for data is scanned as system in the PMS. if (ai.isSystemApp() || ai.isSystemExt()) { - return fulfilledPolicies | IIdmap2.POLICY_SYSTEM_PARTITION; + return fulfilledPolicies | OverlayablePolicy.SYSTEM_PARTITION; } return fulfilledPolicies; } + + private boolean matchesActorSignature(@NonNull PackageInfo targetPackage, + @NonNull PackageInfo overlayPackage, int userId) { + String targetOverlayableName = overlayPackage.targetOverlayableName; + if (targetOverlayableName != null) { + try { + OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget( + targetPackage.packageName, targetOverlayableName, userId); + if (overlayableInfo != null) { + String actorPackageName = OverlayActorEnforcer.getPackageNameForActor( + overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first; + if (mOverlayableCallback.signaturesMatching(actorPackageName, + overlayPackage.packageName, userId)) { + return true; + } + } + } catch (IOException ignored) { + } + } + + return false; + } } diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index 4c85603a719c..40efb7cd96d7 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -17,7 +17,6 @@ package com.android.server.om; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.om.OverlayInfo; import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; @@ -46,7 +45,7 @@ public class OverlayActorEnforcer { // By default, the reason is not logged to prevent leaks of why it failed private static final boolean DEBUG_REASON = false; - private final VerifyCallback mVerifyCallback; + private final OverlayableInfoCallback mOverlayableCallback; /** * @return nullable actor result with {@link ActorState} failure status @@ -80,8 +79,8 @@ public class OverlayActorEnforcer { return Pair.create(packageName, ActorState.ALLOWED); } - public OverlayActorEnforcer(@NonNull VerifyCallback verifyCallback) { - mVerifyCallback = verifyCallback; + public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) { + mOverlayableCallback = overlayableCallback; } void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName, @@ -117,7 +116,7 @@ public class OverlayActorEnforcer { return ActorState.ALLOWED; } - String[] callingPackageNames = mVerifyCallback.getPackagesForUid(callingUid); + String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid); if (ArrayUtils.isEmpty(callingPackageNames)) { return ActorState.NO_PACKAGES_FOR_UID; } @@ -132,12 +131,12 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(targetOverlayableName)) { try { - if (mVerifyCallback.doesTargetDefineOverlayable(targetPackageName, userId)) { + if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) { return ActorState.MISSING_TARGET_OVERLAYABLE_NAME; } else { // If there's no overlayable defined, fallback to the legacy permission check try { - mVerifyCallback.enforcePermission( + mOverlayableCallback.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -153,7 +152,7 @@ public class OverlayActorEnforcer { OverlayableInfo targetOverlayable; try { - targetOverlayable = mVerifyCallback.getOverlayableForTarget(targetPackageName, + targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName, targetOverlayableName, userId); } catch (IOException e) { return ActorState.UNABLE_TO_GET_TARGET; @@ -167,7 +166,7 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(actor)) { // If there's no actor defined, fallback to the legacy permission check try { - mVerifyCallback.enforcePermission( + mOverlayableCallback.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -177,7 +176,7 @@ public class OverlayActorEnforcer { } } - Map<String, Map<String, String>> namedActors = mVerifyCallback.getNamedActors(); + Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors(); Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors); ActorState actorUriState = actorUriPair.second; if (actorUriState != ActorState.ALLOWED) { @@ -185,7 +184,7 @@ public class OverlayActorEnforcer { } String packageName = actorUriPair.first; - PackageInfo packageInfo = mVerifyCallback.getPackageInfo(packageName, userId); + PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId); if (packageInfo == null) { return ActorState.MISSING_APP_INFO; } @@ -211,7 +210,7 @@ public class OverlayActorEnforcer { * For easier logging/debugging, a set of all possible failure/success states when running * enforcement. */ - enum ActorState { + public enum ActorState { ALLOWED, INVALID_ACTOR, MISSING_NAMESPACE, @@ -228,53 +227,4 @@ public class OverlayActorEnforcer { UNABLE_TO_GET_TARGET, MISSING_LEGACY_PERMISSION } - - /** - * Delegate to the system for querying information about packages. - */ - public interface VerifyCallback { - - /** - * Read from the APK and AndroidManifest of a package to return the overlayable defined for - * a given name. - * - * @throws IOException if the target can't be read - */ - @Nullable - OverlayableInfo getOverlayableForTarget(@NonNull String packageName, - @Nullable String targetOverlayableName, int userId) - throws IOException; - - /** - * @see android.content.pm.PackageManager#getPackagesForUid(int) - */ - @Nullable - String[] getPackagesForUid(int uid); - - /** - * @param userId user to filter package visibility by - * @see android.content.pm.PackageManager#getPackageInfo(String, int) - */ - @Nullable - PackageInfo getPackageInfo(@NonNull String packageName, int userId); - - /** - * @return map of system pre-defined, uniquely named actors; keys are namespace, - * value maps actor name to package name - */ - @NonNull - Map<String, Map<String, String>> getNamedActors(); - - /** - * @return true if the target package has declared an overlayable - */ - boolean doesTargetDefineOverlayable(String targetPackageName, int userId) - throws RemoteException, IOException; - - /** - * @throws SecurityException containing message if the caller doesn't have the given - * permission - */ - void enforcePermission(String permission, String message) throws SecurityException; - } } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index f22128533ac2..c81f7cd4a8b4 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -226,7 +226,7 @@ public final class OverlayManagerService extends SystemService { private final AtomicFile mSettingsFile; - private final PackageManagerHelper mPackageManager; + private final PackageManagerHelperImpl mPackageManager; private final UserManagerService mUserManager; @@ -244,7 +244,7 @@ public final class OverlayManagerService extends SystemService { traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService"); mSettingsFile = new AtomicFile( new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays"); - mPackageManager = new PackageManagerHelper(context); + mPackageManager = new PackageManagerHelperImpl(context); mUserManager = UserManagerService.getInstance(); IdmapManager im = new IdmapManager(mPackageManager); mSettings = new OverlayManagerSettings(); @@ -1053,14 +1053,8 @@ public final class OverlayManagerService extends SystemService { } } - /** - * Delegate for {@link android.content.pm.PackageManager} and {@link PackageManagerInternal} - * functionality, separated for easy testing. - * - * @hide - */ - public static final class PackageManagerHelper implements - OverlayManagerServiceImpl.PackageManagerHelper, OverlayActorEnforcer.VerifyCallback { + private static final class PackageManagerHelperImpl implements PackageManagerHelper, + OverlayableInfoCallback { private final Context mContext; private final IPackageManager mPackageManager; @@ -1073,7 +1067,7 @@ public final class OverlayManagerService extends SystemService { // behind until all pending intents have been processed. private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>(); - PackageManagerHelper(Context context) { + PackageManagerHelperImpl(Context context) { mContext = context; mPackageManager = getPackageManager(); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); @@ -1132,7 +1126,7 @@ public final class OverlayManagerService extends SystemService { @Nullable @Override public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, - @Nullable String targetOverlayableName, int userId) + @NonNull String targetOverlayableName, int userId) throws IOException { PackageInfo packageInfo = getPackageInfo(packageName, userId); if (packageInfo == null) { diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 2493057e0121..5734271ecb83 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -18,7 +18,6 @@ package com.android.server.om; import static android.content.om.OverlayInfo.STATE_DISABLED; import static android.content.om.OverlayInfo.STATE_ENABLED; -import static android.content.om.OverlayInfo.STATE_ENABLED_IMMUTABLE; import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; import static android.content.om.OverlayInfo.STATE_NO_IDMAP; import static android.content.om.OverlayInfo.STATE_OVERLAY_IS_BEING_REPLACED; @@ -806,11 +805,4 @@ final class OverlayManagerServiceImpl { **/ void onOverlaysChanged(@NonNull String targetPackage, int userId); } - - interface PackageManagerHelper { - PackageInfo getPackageInfo(@NonNull String packageName, int userId); - boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2, - int userId); - List<PackageInfo> getOverlayPackages(int userId); - } } diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java new file mode 100644 index 000000000000..6b818849c257 --- /dev/null +++ b/services/core/java/com/android/server/om/OverlayableInfoCallback.java @@ -0,0 +1,85 @@ +/* + * 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.om; + + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.om.OverlayableInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.RemoteException; + +import com.android.server.pm.PackageManagerServiceUtils; + +import java.io.IOException; +import java.util.Map; + +/** + * Delegate to the system for querying information about overlayables and packages. + */ +public interface OverlayableInfoCallback { + + /** + * Read from the APK and AndroidManifest of a package to return the overlayable defined for + * a given name. + * + * @throws IOException if the target can't be read + */ + @Nullable + OverlayableInfo getOverlayableForTarget(@NonNull String packageName, + @NonNull String targetOverlayableName, int userId) + throws IOException; + + /** + * @see PackageManager#getPackagesForUid(int) + */ + @Nullable + String[] getPackagesForUid(int uid); + + /** + * @param userId user to filter package visibility by + * @see PackageManager#getPackageInfo(String, int) + */ + @Nullable + PackageInfo getPackageInfo(@NonNull String packageName, int userId); + + /** + * @return map of system pre-defined, uniquely named actors; keys are namespace, + * value maps actor name to package name + */ + @NonNull + Map<String, Map<String, String>> getNamedActors(); + + /** + * @return true if the target package has declared an overlayable + */ + boolean doesTargetDefineOverlayable(String targetPackageName, int userId) + throws RemoteException, IOException; + + /** + * @throws SecurityException containing message if the caller doesn't have the given + * permission + */ + void enforcePermission(String permission, String message) throws SecurityException; + + /** + * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages + * in the system returns {@link PackageManager#SIGNATURE_MATCH} + */ + boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); +} diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java new file mode 100644 index 000000000000..ec9c5e64e390 --- /dev/null +++ b/services/core/java/com/android/server/om/PackageManagerHelper.java @@ -0,0 +1,36 @@ +/* + * 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.om; + +import android.annotation.NonNull; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; + +import java.util.List; + +/** + * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality, + * separated for easy testing. + * + * @hide + */ +interface PackageManagerHelper { + PackageInfo getPackageInfo(@NonNull String packageName, int userId); + boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); + List<PackageInfo> getOverlayPackages(int userId); +} diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java index 1e2d52d76697..6c2d77cac6d3 100644 --- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java +++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java @@ -276,6 +276,11 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } @Override + public void onScreenshotTaken(boolean success) throws RemoteException { + mListener.onScreenshotTaken(success); + } + + @Override public void binderDied() { synchronized (mLock) { if (!mDone) { diff --git a/services/core/java/com/android/server/people/PeopleServiceInternal.java b/services/core/java/com/android/server/people/PeopleServiceInternal.java index 31fa4d192278..8b4740b33c91 100644 --- a/services/core/java/com/android/server/people/PeopleServiceInternal.java +++ b/services/core/java/com/android/server/people/PeopleServiceInternal.java @@ -17,6 +17,7 @@ package com.android.server.people; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.os.CancellationSignal; import android.service.appprediction.IPredictionService; @@ -34,16 +35,17 @@ public abstract class PeopleServiceInternal extends IPredictionService.Stub { @NonNull CancellationSignal signal); /** - * The number conversation infos will be dynamic, based on the currently installed apps on the - * device. All of which should be combined into a single blob to be backed up. + * Returns a backup payload that contains conversation infos. The number conversation infos will + * be dynamic, based on the currently installed apps on the device. All of which should be + * combined into a single blob to be backed up. */ - public abstract byte[] backupConversationInfos(@UserIdInt int userId); + @Nullable + public abstract byte[] getBackupPayload(@UserIdInt int userId); /** - * Multiple conversation infos may exist in the restore payload, child classes are required to - * manage the restoration based on how individual conversation infos were originally combined - * during backup. + * Restores conversation infos stored in payload blob. Multiple conversation infos may exist in + * the restore payload, child classes are required to manage the restoration based on how + * individual conversation infos were originally combined during backup. */ - public abstract void restoreConversationInfos(@UserIdInt int userId, @NonNull String key, - @NonNull byte[] payload); + public abstract void restore(@UserIdInt int userId, @NonNull byte[] payload); } diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index e86a42c284b6..f497f114c05f 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -57,6 +57,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import com.android.server.IntentResolver; import com.android.server.pm.parsing.PackageInfoUtils; +import com.android.server.pm.parsing.PackageInfoUtils.CachedApplicationInfoGenerator; import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.PrintWriter; @@ -273,9 +274,7 @@ public class ComponentResolver { return null; } List<ProviderInfo> providerList = null; - - // Map from a package name to the corresponding app info. - ArrayMap<String, ApplicationInfo> appInfos = null; + CachedApplicationInfoGenerator appInfoGenerator = null; synchronized (mLock) { for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) { final ParsedProvider p = mProviders.mProviders.valueAt(i); @@ -304,26 +303,15 @@ public class ComponentResolver { && (p.getMetaData() == null || !p.getMetaData().containsKey(metaDataKey))) { continue; } - - // Make sure we have AppInfo for this provider. + if (appInfoGenerator == null) { + appInfoGenerator = new CachedApplicationInfoGenerator(); + } final PackageUserState state = ps.readUserState(userId); - ApplicationInfo appInfo = - (appInfos == null) ? null : appInfos.get(pkg.getPackageName()); + final ApplicationInfo appInfo = + appInfoGenerator.generate(pkg, flags, state, userId, ps); if (appInfo == null) { - appInfo = PackageInfoUtils.generateApplicationInfo( - pkg, flags, state, userId, ps); - if (appInfo == null) { - // In this case, we should avoid calling generateApplicationInfo() for - // the same package in subsequent iterations, but appInfo shouldn't be null - // here, so we don't bother. - continue; - } - if (appInfos == null) { - appInfos = new ArrayMap<>(4); - } - appInfos.put(pkg.getPackageName(), appInfo); + continue; } - // At this point, appInfo != null. final ProviderInfo info = PackageInfoUtils.generateProviderInfo( pkg, p, flags, state, appInfo, userId, ps); @@ -355,14 +343,20 @@ public class ComponentResolver { if (pkg == null) { return null; } - return PackageInfoUtils.generateProviderInfo(pkg, p, flags, - ps.readUserState(userId), userId, ps); + final PackageUserState state = ps.readUserState(userId); + ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo( + pkg, flags, state, userId, ps); + if (appInfo == null) { + return null; + } + return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, appInfo, userId, ps); } } void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo, boolean safeMode, int userId) { synchronized (mLock) { + CachedApplicationInfoGenerator appInfoGenerator = null; for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) { final ParsedProvider p = mProvidersByAuthority.valueAt(i); if (!p.isSyncable()) { @@ -384,9 +378,18 @@ public class ComponentResolver { if (safeMode && !pkg.isSystem()) { continue; } - final ProviderInfo info = - PackageInfoUtils.generateProviderInfo(pkg, p, 0, - ps.readUserState(userId), userId, ps); + if (appInfoGenerator == null) { + appInfoGenerator = new CachedApplicationInfoGenerator(); + } + final PackageUserState state = ps.readUserState(userId); + final ApplicationInfo appInfo = + appInfoGenerator.generate(pkg, 0, state, userId, ps); + if (appInfo == null) { + continue; + } + + final ProviderInfo info = PackageInfoUtils.generateProviderInfo( + pkg, p, 0, state, appInfo, userId, ps); if (info == null) { continue; } @@ -1731,8 +1734,13 @@ public class ComponentResolver { if (userState.instantApp && ps.isUpdateAvailable()) { return null; } + final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo( + pkg, mFlags, userState, userId, ps); + if (appInfo == null) { + return null; + } ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider, mFlags, - userState, userId, ps); + userState, appInfo, userId, ps); if (pi == null) { return null; } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 41988d6c5786..5cc5059613a8 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1689,8 +1689,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } mRelinquished = true; - return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, - localObserver, params, mInstallerUid, mInstallSource, user, mSigningDetails); + return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, localObserver, + sessionId, params, mInstallerUid, mInstallSource, user, mSigningDetails); } private static void maybeRenameFile(File from, File to) throws PackageManagerException { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4eac79cff8b5..c34e45e1e84a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -213,7 +213,6 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; -import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.content.pm.parsing.ParsingPackageUtils; import android.content.pm.parsing.component.ParsedActivity; import android.content.pm.parsing.component.ParsedInstrumentation; @@ -1967,6 +1966,7 @@ public class PackageManagerService extends IPackageManager.Stub } case ENABLE_ROLLBACK_TIMEOUT: { final int enableRollbackToken = msg.arg1; + final int sessionId = msg.arg2; final InstallParams params = mPendingEnableRollback.get(enableRollbackToken); if (params != null) { final InstallArgs args = params.mArgs; @@ -1982,8 +1982,8 @@ public class PackageManagerService extends IPackageManager.Stub Intent rollbackTimeoutIntent = new Intent( Intent.ACTION_CANCEL_ENABLE_ROLLBACK); rollbackTimeoutIntent.putExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, - enableRollbackToken); + PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, + sessionId); rollbackTimeoutIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcastAsUser(rollbackTimeoutIntent, UserHandle.SYSTEM, @@ -5459,7 +5459,13 @@ public class PackageManagerService extends IPackageManager.Stub return null; } PackageUserState state = ps.readUserState(userId); - return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId, ps); + final ApplicationInfo appInfo = PackageInfoUtils.generateApplicationInfo( + pkg, flags, state, userId, ps); + if (appInfo == null) { + return null; + } + return PackageInfoUtils.generateProviderInfo( + pkg, p, flags, state, appInfo, userId, ps); } } return null; @@ -6826,12 +6832,16 @@ public class PackageManagerService extends IPackageManager.Stub final boolean isTargetHiddenFromInstantApp = !isTargetVisibleToInstantApp || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp); - final boolean blockResolution = + final boolean blockInstantResolution = !isTargetSameInstantApp && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); - if (!blockResolution) { + final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp + && !resolveForStart && shouldFilterApplicationLocked( + getPackageSettingInternal(ai.applicationInfo.packageName, + Process.SYSTEM_UID), filterCallingUid, userId); + if (!blockInstantResolution && !blockNormalResolution) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); @@ -7215,9 +7225,17 @@ public class PackageManagerService extends IPackageManager.Stub resolveInfos.set(i, installerInfo); continue; } - // caller is a full app, don't need to apply any other filtering + // caller is a full app if (ephemeralPkgName == null) { - continue; + SettingBase callingSetting = + mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid)); + PackageSetting resolvedSetting = + getPackageSettingInternal(info.activityInfo.packageName, 0); + if (resolveForStart + || !mAppsFilter.shouldFilterApplication( + filterCallingUid, callingSetting, resolvedSetting, userId)) { + continue; + } } else if (ephemeralPkgName.equals(info.activityInfo.packageName)) { // caller is same app; don't need to apply any other filtering continue; @@ -7907,12 +7925,17 @@ public class PackageManagerService extends IPackageManager.Stub & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; final boolean isTargetHiddenFromInstantApp = (si.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0; - final boolean blockResolution = + final boolean blockInstantResolution = !isTargetSameInstantApp && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); - if (!blockResolution) { + + final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp + && shouldFilterApplicationLocked( + getPackageSettingInternal(si.applicationInfo.packageName, + Process.SYSTEM_UID), callingUid, userId); + if (!blockInstantResolution && !blockNormalResolution) { final ResolveInfo ri = new ResolveInfo(); ri.serviceInfo = si; list.add(ri); @@ -7931,8 +7954,7 @@ public class PackageManagerService extends IPackageManager.Stub return Collections.emptyList(); } return applyPostServiceResolutionFilter( - resolveInfos, - instantAppPkgName); + resolveInfos, instantAppPkgName, userId, callingUid); } final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { @@ -7943,20 +7965,26 @@ public class PackageManagerService extends IPackageManager.Stub return Collections.emptyList(); } return applyPostServiceResolutionFilter( - resolveInfos, - instantAppPkgName); + resolveInfos, instantAppPkgName, userId, callingUid); } return Collections.emptyList(); } } private List<ResolveInfo> applyPostServiceResolutionFilter(List<ResolveInfo> resolveInfos, - String instantAppPkgName) { - if (instantAppPkgName == null) { - return resolveInfos; - } + String instantAppPkgName, @UserIdInt int userId, int filterCallingUid) { for (int i = resolveInfos.size() - 1; i >= 0; i--) { final ResolveInfo info = resolveInfos.get(i); + if (instantAppPkgName == null) { + SettingBase callingSetting = + mSettings.getSettingLPr(UserHandle.getAppId(filterCallingUid)); + PackageSetting resolvedSetting = + getPackageSettingInternal(info.serviceInfo.packageName, 0); + if (!mAppsFilter.shouldFilterApplication( + filterCallingUid, callingSetting, resolvedSetting, userId)) { + continue; + } + } final boolean isEphemeralApp = info.serviceInfo.applicationInfo.isInstantApp(); // allow services that are defined in the provided package if (isEphemeralApp && instantAppPkgName.equals(info.serviceInfo.packageName)) { @@ -8039,7 +8067,11 @@ public class PackageManagerService extends IPackageManager.Stub && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp) || (matchVisibleToInstantAppOnly && isCallerInstantApp && isTargetHiddenFromInstantApp)); - if (!blockResolution) { + final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp + && shouldFilterApplicationLocked( + getPackageSettingInternal(pi.applicationInfo.packageName, + Process.SYSTEM_UID), callingUid, userId); + if (!blockResolution && !blockNormalResolution) { final ResolveInfo ri = new ResolveInfo(); ri.providerInfo = pi; list.add(ri); @@ -8058,8 +8090,7 @@ public class PackageManagerService extends IPackageManager.Stub return Collections.emptyList(); } return applyPostContentProviderResolutionFilter( - resolveInfos, - instantAppPkgName); + resolveInfos, instantAppPkgName, userId, callingUid); } final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { @@ -8070,20 +8101,29 @@ public class PackageManagerService extends IPackageManager.Stub return Collections.emptyList(); } return applyPostContentProviderResolutionFilter( - resolveInfos, - instantAppPkgName); + resolveInfos, instantAppPkgName, userId, callingUid); } return Collections.emptyList(); } } private List<ResolveInfo> applyPostContentProviderResolutionFilter( - List<ResolveInfo> resolveInfos, String instantAppPkgName) { - if (instantAppPkgName == null) { - return resolveInfos; - } + List<ResolveInfo> resolveInfos, String instantAppPkgName, + @UserIdInt int userId, int callingUid) { for (int i = resolveInfos.size() - 1; i >= 0; i--) { final ResolveInfo info = resolveInfos.get(i); + + if (instantAppPkgName == null) { + SettingBase callingSetting = + mSettings.getSettingLPr(UserHandle.getAppId(callingUid)); + PackageSetting resolvedSetting = + getPackageSettingInternal(info.providerInfo.packageName, 0); + if (!mAppsFilter.shouldFilterApplication( + callingUid, callingSetting, resolvedSetting, userId)) { + continue; + } + } + final boolean isEphemeralApp = info.providerInfo.applicationInfo.isInstantApp(); // allow providers that are defined in the provided package if (isEphemeralApp && instantAppPkgName.equals(info.providerInfo.packageName)) { @@ -10945,17 +10985,22 @@ public class PackageManagerService extends IPackageManager.Stub if (createNewPackage) { final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0; + + // Flags contain system values stored in the server variant of AndroidPackage, + // and so the server-side PackageInfoUtils is still called, even without a + // PackageSetting to pass in. + int pkgFlags = PackageInfoUtils.appInfoFlags(parsedPackage, null); + int pkgPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(parsedPackage, null); + // REMOVE SharedUserSetting from method; update in a separate call pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(), AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage), AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage), - parsedPackage.getVersionCode(), - PackageInfoWithoutStateUtils.appInfoFlags(parsedPackage), - PackageInfoWithoutStateUtils.appInfoPrivateFlags(parsedPackage), - user, true /*allowInstall*/, instantApp, - virtualPreload, UserManagerService.getInstance(), usesStaticLibraries, + parsedPackage.getVersionCode(), pkgFlags, pkgPrivateFlags, user, + true /*allowInstall*/, instantApp, virtualPreload, + UserManagerService.getInstance(), usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions(), parsedPackage.getMimeGroups()); } else { // make a deep copy to avoid modifying any existing system state. @@ -11774,14 +11819,22 @@ public class PackageManagerService extends IPackageManager.Stub final String pkgName = pkg.getPackageName(); if (mCustomResolverComponentName != null && mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) { - setUpCustomResolverActivity(pkg); + setUpCustomResolverActivity(pkg, pkgSetting); } if (pkg.getPackageName().equals("android")) { synchronized (mLock) { // Set up information for our fall-back user intent resolution activity. mPlatformPackage = pkg; + + // The instance stored in PackageManagerService is special cased to be non-user + // specific, so initialize all the needed fields here. mAndroidApplication = pkg.toAppInfoWithoutState(); + mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting); + mAndroidApplication.privateFlags = + PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting); + mAndroidApplication.initForUser(UserHandle.USER_SYSTEM); + if (!mResolverReplaced) { mResolveActivity.applicationInfo = mAndroidApplication; mResolveActivity.name = ResolverActivity.class.getName(); @@ -11943,11 +11996,20 @@ public class PackageManagerService extends IPackageManager.Stub Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - private void setUpCustomResolverActivity(AndroidPackage pkg) { + private void setUpCustomResolverActivity(AndroidPackage pkg, PackageSetting pkgSetting) { synchronized (mLock) { mResolverReplaced = true; + + // The instance created in PackageManagerService is special cased to be non-user + // specific, so initialize all the needed fields here. + ApplicationInfo appInfo = pkg.toAppInfoWithoutState(); + appInfo.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting); + appInfo.privateFlags = + PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting); + appInfo.initForUser(UserHandle.USER_SYSTEM); + // Set up information for custom user intent resolution activity. - mResolveActivity.applicationInfo = pkg.toAppInfoWithoutState(); + mResolveActivity.applicationInfo = appInfo; mResolveActivity.name = mCustomResolverComponentName.getClassName(); mResolveActivity.packageName = pkg.getPackageName(); mResolveActivity.processName = pkg.getProcessName(); @@ -14237,6 +14299,7 @@ public class PackageManagerService extends IPackageManager.Stub final long requiredInstalledVersionCode; final boolean forceQueryableOverride; final int mDataLoaderType; + final int mSessionId; InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer, int installFlags, InstallSource installSource, String volumeUuid, @@ -14260,6 +14323,7 @@ public class PackageManagerService extends IPackageManager.Stub this.requiredInstalledVersionCode = requiredInstalledVersionCode; this.forceQueryableOverride = false; this.mDataLoaderType = dataLoaderType; + this.mSessionId = -1; } InstallParams(ActiveInstallSession activeInstallSession) { @@ -14295,6 +14359,7 @@ public class PackageManagerService extends IPackageManager.Stub forceQueryableOverride = sessionParams.forceQueryableOverride; mDataLoaderType = (sessionParams.dataLoaderParams != null) ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE; + mSessionId = activeInstallSession.getSessionId(); } @Override @@ -14526,13 +14591,9 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, enableRollbackToken); enableRollbackIntent.putExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, - installFlags); - enableRollbackIntent.putExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, - getRollbackUser().getIdentifier()); - enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), - PACKAGE_MIME_TYPE); + PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, + mSessionId); + enableRollbackIntent.setType(PACKAGE_MIME_TYPE); enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // Allow the broadcast to be sent before boot complete. @@ -14558,6 +14619,7 @@ public class PackageManagerService extends IPackageManager.Stub final Message msg = mHandler.obtainMessage( ENABLE_ROLLBACK_TIMEOUT); msg.arg1 = enableRollbackToken; + msg.arg2 = mSessionId; mHandler.sendMessageDelayed(msg, rollbackTimeout); } }, null, 0, null, null); @@ -24567,6 +24629,7 @@ public class PackageManagerService extends IPackageManager.Stub private final String mPackageName; private final File mStagedDir; private final IPackageInstallObserver2 mObserver; + private final int mSessionId; private final PackageInstaller.SessionParams mSessionParams; private final int mInstallerUid; @NonNull private final InstallSource mInstallSource; @@ -24574,11 +24637,12 @@ public class PackageManagerService extends IPackageManager.Stub private final SigningDetails mSigningDetails; ActiveInstallSession(String packageName, File stagedDir, IPackageInstallObserver2 observer, - PackageInstaller.SessionParams sessionParams, int installerUid, + int sessionId, PackageInstaller.SessionParams sessionParams, int installerUid, InstallSource installSource, UserHandle user, SigningDetails signingDetails) { mPackageName = packageName; mStagedDir = stagedDir; mObserver = observer; + mSessionId = sessionId; mSessionParams = sessionParams; mInstallerUid = installerUid; mInstallSource = Preconditions.checkNotNull(installSource); @@ -24598,6 +24662,10 @@ public class PackageManagerService extends IPackageManager.Stub return mObserver; } + public int getSessionId() { + return mSessionId; + } + public PackageInstaller.SessionParams getSessionParams() { return mSessionParams; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 24533184f5bf..fa1da27e7531 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -33,6 +33,7 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.compat.ChangeIdStateCache; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; @@ -441,6 +442,7 @@ public final class Settings { private static void invalidatePackageCache() { PackageManager.invalidatePackageInfoCache(); + ChangeIdStateCache.invalidate(); } PackageSetting getPackageLPr(String pkgName) { diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java index f5ce0804236d..d3f668c5f4d3 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -48,7 +48,7 @@ import android.content.pm.parsing.component.ParsedService; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Pair; +import android.util.Slog; import com.android.internal.util.ArrayUtils; import com.android.server.pm.PackageSetting; @@ -72,6 +72,7 @@ import java.util.Set; * @hide **/ public class PackageInfoUtils { + private static final String TAG = PackageParser2.TAG; /** * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. @@ -108,12 +109,9 @@ public class PackageInfoUtils { return null; } - PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponents(pkg, gids, flags, - firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, apexInfo, - applicationInfo); - if (info == null) { - return null; - } + PackageInfo info = PackageInfoWithoutStateUtils.generateWithoutComponentsUnchecked(pkg, + gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions, state, userId, + apexInfo, applicationInfo); info.isStub = pkg.isStub(); info.coreApp = pkg.isCoreApp(); @@ -218,11 +216,8 @@ public class PackageInfoUtils { return null; } - ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfo(pkg, flags, - state, userId); - if (info == null) { - return null; - } + ApplicationInfo info = PackageInfoWithoutStateUtils.generateApplicationInfoUnchecked(pkg, + flags, state, userId); if (pkgSetting != null) { // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up @@ -265,12 +260,13 @@ public class PackageInfoUtils { if (applicationInfo == null) { applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); } - ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfo(pkg, a, flags, state, - applicationInfo, userId); - if (info == null) { + + if (applicationInfo == null) { return null; } + ActivityInfo info = + PackageInfoWithoutStateUtils.generateActivityInfoUnchecked(a, applicationInfo); assignSharedFieldsForComponentInfo(info, a, pkgSetting); return info; } @@ -300,53 +296,39 @@ public class PackageInfoUtils { if (applicationInfo == null) { applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); } - ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfo(pkg, s, flags, state, - applicationInfo, userId); - if (info == null) { + if (applicationInfo == null) { return null; } + ServiceInfo info = + PackageInfoWithoutStateUtils.generateServiceInfoUnchecked(s, applicationInfo); assignSharedFieldsForComponentInfo(info, s, pkgSetting); return info; } /** * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. - * - * @deprecated use {@link #generateProviderInfo( - * AndroidPackage, ParsedProvider, int, PackageUserState, ApplicationInfo, int, PackageSetting)} - * instead and pass {@link ApplicationInfo} explicitly to avoid generating duplicate instances - * of it. - */ - @Nullable - @Deprecated - public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p, - @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId, - @Nullable PackageSetting pkgSetting) { - return generateProviderInfo(pkg, p, flags, state, null, userId, pkgSetting); - } - - /** - * @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage. */ @Nullable public static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, PackageUserState state, - @Nullable ApplicationInfo applicationInfo, int userId, + @NonNull ApplicationInfo applicationInfo, int userId, @Nullable PackageSetting pkgSetting) { if (p == null) return null; if (!checkUseInstalledOrHidden(pkg, pkgSetting, state, flags)) { return null; } - if (applicationInfo == null) { + if (applicationInfo == null || !pkg.getPackageName().equals(applicationInfo.packageName)) { + Slog.wtf(TAG, "AppInfo's package name is different. Expected=" + pkg.getPackageName() + + " actual=" + (applicationInfo == null ? "(null AppInfo)" + : applicationInfo.packageName)); applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting); } - ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfo(pkg, p, flags, state, - applicationInfo, userId); - if (info == null) { + if (applicationInfo == null) { return null; } - + ProviderInfo info = PackageInfoWithoutStateUtils.generateProviderInfoUnchecked(p, flags, + applicationInfo); assignSharedFieldsForComponentInfo(info, p, pkgSetting); return info; } @@ -486,4 +468,29 @@ public class PackageInfoUtils { | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY); // @formatter:on } + + /** + * Wraps {@link PackageInfoUtils#generateApplicationInfo} with a cache. + */ + public static class CachedApplicationInfoGenerator { + // Map from a package name to the corresponding app info. + private ArrayMap<String, ApplicationInfo> mCache = new ArrayMap<>(); + + /** + * {@link PackageInfoUtils#generateApplicationInfo} with a cache. + */ + @Nullable + public ApplicationInfo generate(AndroidPackage pkg, + @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId, + @Nullable PackageSetting pkgSetting) { + ApplicationInfo appInfo = mCache.get(pkg.getPackageName()); + if (appInfo != null) { + return appInfo; + } + appInfo = PackageInfoUtils.generateApplicationInfo( + pkg, flags, state, userId, pkgSetting); + mCache.put(pkg.getPackageName(), appInfo); + return appInfo; + } + } } diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java index f99791a28f46..d561b9c1ffdd 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java +++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java @@ -42,7 +42,7 @@ import java.io.File; */ public class PackageParser2 { - private static final String TAG = "PackageParser2"; + static final String TAG = "PackageParser2"; private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE; private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100; diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 48dd9e6f86ec..2feddb6a4fe3 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -733,7 +733,7 @@ public final class DefaultPermissionGrantPolicy { if (!TextUtils.isEmpty(contentCapturePackageName)) { grantPermissionsToSystemPackage(contentCapturePackageName, userId, PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, - CONTACTS_PERMISSIONS); + CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS); } // Atthention Service diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index f647b6a94bf6..4a85027854d6 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -4471,6 +4471,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { @Override public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) { synchronized (mLock) { + if (delegate != null || mCheckPermissionDelegate != null) { + PackageManager.invalidatePackageInfoCache(); + } mCheckPermissionDelegate = delegate; } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index b40c2c1d343b..1b5cc6a248e3 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3090,7 +3090,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { event.getAction(), fallbackAction.keyCode, event.getRepeatCount(), fallbackAction.metaState, event.getDeviceId(), event.getScanCode(), - flags, event.getSource(), event.getDisplayId(), null /* hmac */, null); + flags, event.getSource(), event.getDisplayId(), null); if (!interceptFallback(focusedToken, fallbackEvent, policyFlags)) { fallbackEvent.recycle(); diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java index 90babcd2a100..6c18c8d04363 100644 --- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java @@ -27,23 +27,18 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYST import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static java.lang.Integer.min; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledAfter; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceManager; +import android.os.Build; import android.os.UserHandle; import android.os.storage.StorageManagerInternal; -import android.util.Log; -import com.android.internal.compat.IPlatformCompat; import com.android.server.LocalServices; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -55,27 +50,6 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; * {@link com.android.packageinstaller.permission.utils.SoftRestrictedPermissionPolicy} */ public abstract class SoftRestrictedPermissionPolicy { - /** - * Enables scoped storage, with exceptions for apps that explicitly request legacy access, or - * apps that hold the {@code android.Manifest.permission#WRITE_MEDIA_STORAGE} permission. - * See https://developer.android.com/training/data-storage#scoped-storage for more information. - */ - @ChangeId - // This change is enabled for apps with targetSDK > {@link android.os.Build.VERSION_CODES.P} - @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.P) - static final long ENABLE_SCOPED_STORAGE = 144914977L; - - /** - * Enforces scoped storage for all apps, preventing individual apps from opting out. This change - * has precedence over {@code ENABLE_SCOPED_STORAGE}. - */ - @ChangeId - // This change is enabled for apps with targetSDK > {@link android.os.Build.VERSION_CODES.Q}. - @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q) - static final long REQUIRE_SCOPED_STORAGE = 131432978L; - - private static final String LOG_TAG = SoftRestrictedPermissionPolicy.class.getSimpleName(); - private static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT = FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT @@ -90,6 +64,41 @@ public abstract class SoftRestrictedPermissionPolicy { }; /** + * TargetSDK is per package. To make sure two apps int the same shared UID do not fight over + * what to set, always compute the combined targetSDK. + * + * @param context A context + * @param appInfo The app that is changed + * @param user The user the app belongs to + * + * @return The minimum targetSDK of all apps sharing the uid of the app + */ + private static int getMinimumTargetSDK(@NonNull Context context, + @NonNull ApplicationInfo appInfo, @NonNull UserHandle user) { + PackageManager pm = context.getPackageManager(); + + int minimumTargetSDK = appInfo.targetSdkVersion; + + String[] uidPkgs = pm.getPackagesForUid(appInfo.uid); + if (uidPkgs != null) { + for (String uidPkg : uidPkgs) { + if (!uidPkg.equals(appInfo.packageName)) { + ApplicationInfo uidPkgInfo; + try { + uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user); + } catch (PackageManager.NameNotFoundException e) { + continue; + } + + minimumTargetSDK = min(minimumTargetSDK, uidPkgInfo.targetSdkVersion); + } + } + } + + return minimumTargetSDK; + } + + /** * Get the policy for a soft restricted permission. * * @param context A context to use @@ -109,10 +118,10 @@ public abstract class SoftRestrictedPermissionPolicy { case READ_EXTERNAL_STORAGE: { final boolean isWhiteListed; boolean shouldApplyRestriction; + final int targetSDK; final boolean hasRequestedLegacyExternalStorage; final boolean shouldPreserveLegacyExternalStorage; final boolean hasWriteMediaStorageGrantedForUid; - final boolean isScopedStorageEnabled; if (appInfo != null) { PackageManager pm = context.getPackageManager(); @@ -124,22 +133,19 @@ public abstract class SoftRestrictedPermissionPolicy { appInfo.uid, context); hasWriteMediaStorageGrantedForUid = hasWriteMediaStorageGrantedForUid( appInfo.uid, context); - final boolean isScopedStorageRequired = - isChangeEnabledForUid(context, appInfo, user, REQUIRE_SCOPED_STORAGE); - isScopedStorageEnabled = - isChangeEnabledForUid(context, appInfo, user, ENABLE_SCOPED_STORAGE) - || isScopedStorageRequired; shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage() && smInternal.hasLegacyExternalStorage(appInfo.uid); + targetSDK = getMinimumTargetSDK(context, appInfo, user); shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0 - || (isScopedStorageRequired && !shouldPreserveLegacyExternalStorage); + || (targetSDK > Build.VERSION_CODES.Q + && !shouldPreserveLegacyExternalStorage); } else { isWhiteListed = false; shouldApplyRestriction = false; + targetSDK = 0; hasRequestedLegacyExternalStorage = false; shouldPreserveLegacyExternalStorage = false; hasWriteMediaStorageGrantedForUid = false; - isScopedStorageEnabled = false; } // We have a check in PermissionPolicyService.PermissionToOpSynchroniser.setUidMode @@ -149,7 +155,7 @@ public abstract class SoftRestrictedPermissionPolicy { return new SoftRestrictedPermissionPolicy() { @Override public boolean mayGrantPermission() { - return isWhiteListed || isScopedStorageEnabled; + return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q; } @Override public int getExtraAppOpCode() { @@ -157,7 +163,7 @@ public abstract class SoftRestrictedPermissionPolicy { } @Override public boolean mayAllowExtraAppOp() { - return !shouldApplyRestriction + return !shouldApplyRestriction && targetSDK <= Build.VERSION_CODES.Q && (hasRequestedLegacyExternalStorage || hasWriteMediaStorageGrantedForUid || shouldPreserveLegacyExternalStorage); @@ -170,26 +176,22 @@ public abstract class SoftRestrictedPermissionPolicy { } case WRITE_EXTERNAL_STORAGE: { final boolean isWhiteListed; - final boolean isScopedStorageEnabled; + final int targetSDK; if (appInfo != null) { final int flags = context.getPackageManager().getPermissionFlags(permission, appInfo.packageName, user); isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; - final boolean isScopedStorageRequired = - isChangeEnabledForUid(context, appInfo, user, REQUIRE_SCOPED_STORAGE); - isScopedStorageEnabled = - isChangeEnabledForUid(context, appInfo, user, ENABLE_SCOPED_STORAGE) - || isScopedStorageRequired; + targetSDK = getMinimumTargetSDK(context, appInfo, user); } else { isWhiteListed = false; - isScopedStorageEnabled = false; + targetSDK = 0; } return new SoftRestrictedPermissionPolicy() { @Override public boolean mayGrantPermission() { - return isWhiteListed || isScopedStorageEnabled; + return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q; } }; } @@ -198,62 +200,6 @@ public abstract class SoftRestrictedPermissionPolicy { } } - /** - * Checks whether an AppCompat change is enabled for all packages sharing a UID with the - * provided application. - * - * @param context A context to use. - * @param appInfo The application for which to check whether the compat change is enabled. - * @param user The user the app belongs to. - * @param changeId A {@link android.compat.annotation.ChangeId} corresponding to the change. - * - * @return true if this change is enabled for all apps sharing the UID of the provided app, - * false otherwise. - */ - private static boolean isChangeEnabledForUid(@NonNull Context context, - @NonNull ApplicationInfo appInfo, @NonNull UserHandle user, long changeId) { - PackageManager pm = context.getPackageManager(); - - String[] uidPackages = pm.getPackagesForUid(appInfo.uid); - if (uidPackages != null) { - for (String uidPackage : uidPackages) { - ApplicationInfo uidPackageInfo; - try { - uidPackageInfo = pm.getApplicationInfoAsUser(uidPackage, 0, user); - } catch (PackageManager.NameNotFoundException e) { - continue; - } - if (!isChangeEnabled(uidPackageInfo, changeId)) { - // At least one package sharing this UID does not have this change enabled. - return false; - } - } - // All packages sharing this UID returned true for {@link #isChangeEnabled()}. - return true; - } else { - Log.w(LOG_TAG, "Check for change " + changeId + " for uid " + appInfo.uid - + " produced no packages. Defaulting to using the information for " - + appInfo.packageName + " only."); - return isChangeEnabled(appInfo, changeId); - } - } - - private static boolean isChangeEnabled(@NonNull ApplicationInfo appInfo, long changeId) { - IBinder binder = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE); - IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(binder); - - final long callingId = Binder.clearCallingIdentity(); - - try { - return platformCompat.isChangeEnabled(changeId, appInfo); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Check for change " + changeId + " failed. Defaulting to enabled.", e); - return true; - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - private static boolean hasUidRequestedLegacyExternalStorage(int uid, @NonNull Context context) { PackageManager packageManager = context.getPackageManager(); String[] packageNames = packageManager.getPackagesForUid(uid); diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 0b95be15f157..199cb4981fe6 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -413,7 +413,6 @@ public class Notifier { // Start input as soon as we start waking up or going to sleep. mInputManagerInternal.setInteractive(interactive); - mInputMethodManagerInternal.setInteractive(interactive); // Notify battery stats. try { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 8483c774cb8e..e6c23b66eba2 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -4213,15 +4213,15 @@ public final class PowerManagerService extends SystemService .SCREEN_BRIGHTNESS_SETTING_LIMITS); proto.write( PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto - .SETTING_MINIMUM, + .SETTING_MINIMUM_FLOAT, mScreenBrightnessSettingMinimum); proto.write( PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto - .SETTING_MAXIMUM, + .SETTING_MAXIMUM_FLOAT, mScreenBrightnessSettingMaximum); proto.write( PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto - .SETTING_DEFAULT, + .SETTING_DEFAULT_FLOAT, mScreenBrightnessSettingDefault); proto.end(screenBrightnessSettingLimitsToken); diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java index 233417da3e00..059861b65e20 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java @@ -16,8 +16,13 @@ package com.android.server.power.batterysaver; import android.annotation.IntDef; +import android.app.UiModeManager; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Configuration; import android.database.ContentObserver; import android.net.Uri; import android.os.BatterySaverPolicyConfig; @@ -183,18 +188,15 @@ public class BatterySaverPolicy extends ContentObserver { private String mEventLogKeys; /** - * Whether vibration should *really* be disabled -- i.e. {@link Policy#disableVibration} - * is true *and* {@link #mAccessibilityEnabled} is false. - */ - @GuardedBy("mLock") - private boolean mDisableVibrationEffective; - - /** * Whether accessibility is currently enabled or not. */ @GuardedBy("mLock") private boolean mAccessibilityEnabled; + /** Whether the phone is projecting in car mode or not. */ + @GuardedBy("mLock") + private boolean mCarModeEnabled; + /** The current default adaptive policy. */ @GuardedBy("mLock") private Policy mDefaultAdaptivePolicy = DEFAULT_ADAPTIVE_POLICY; @@ -207,6 +209,13 @@ public class BatterySaverPolicy extends ContentObserver { @GuardedBy("mLock") private Policy mFullPolicy = DEFAULT_FULL_POLICY; + /** + * The current effective policy. This is based on the current policy level's policy, with any + * required adjustments. + */ + @GuardedBy("mLock") + private Policy mEffectivePolicy = OFF_POLICY; + @IntDef(prefix = {"POLICY_LEVEL_"}, value = { POLICY_LEVEL_OFF, POLICY_LEVEL_ADAPTIVE, @@ -230,6 +239,20 @@ public class BatterySaverPolicy extends ContentObserver { private final ContentResolver mContentResolver; private final BatterySavingStats mBatterySavingStats; + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED: + setCarModeEnabled(true); + break; + case UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED: + setCarModeEnabled(false); + break; + } + } + }; + @GuardedBy("mLock") private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>(); @@ -263,16 +286,25 @@ public class BatterySaverPolicy extends ContentObserver { final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class); - acm.addAccessibilityStateChangeListener((enabled) -> { - synchronized (mLock) { - mAccessibilityEnabled = enabled; - } - refreshSettings(); - }); - final boolean enabled = acm.isEnabled(); + acm.addAccessibilityStateChangeListener((enabled) -> setAccessibilityEnabled(enabled)); + final boolean accessibilityEnabled = acm.isEnabled(); synchronized (mLock) { - mAccessibilityEnabled = enabled; + mAccessibilityEnabled = accessibilityEnabled; } + + final IntentFilter filter = new IntentFilter( + UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED); + filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED); + // The ENTER/EXIT_CAR_MODE_PRIORITIZED intents are sent to UserHandle.ALL, so no need to + // register as all users here. + mContext.registerReceiver(mBroadcastReceiver, filter); + final boolean carModeEnabled = + mContext.getSystemService(UiModeManager.class).getCurrentModeType() + == Configuration.UI_MODE_TYPE_CAR; + synchronized (mLock) { + mCarModeEnabled = carModeEnabled; + } + onChange(true, null); } @@ -299,13 +331,34 @@ public class BatterySaverPolicy extends ContentObserver { PowerManager.invalidatePowerSaveModeCaches(); } + /** + * Notifies listeners of a policy change on the handler thread only if the current policy level + * is not {@link POLICY_LEVEL_OFF}. + */ + private void maybeNotifyListenersOfPolicyChange() { + final BatterySaverPolicyListener[] listeners; + synchronized (mLock) { + if (getPolicyLevelLocked() == POLICY_LEVEL_OFF) { + // Current policy is OFF, so there's no change to notify listeners of. + return; + } + // Don't call out to listeners with the lock held. + listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]); + } + + mHandler.post(() -> { + for (BatterySaverPolicyListener listener : listeners) { + listener.onBatterySaverPolicyChanged(this); + } + }); + } + @Override public void onChange(boolean selfChange, Uri uri) { refreshSettings(); } private void refreshSettings() { - final BatterySaverPolicyListener[] listeners; synchronized (mLock) { // Load the non-device-specific setting. final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS); @@ -334,16 +387,9 @@ public class BatterySaverPolicy extends ContentObserver { // Nothing of note changed. return; } - - listeners = mListeners.toArray(new BatterySaverPolicyListener[0]); } - // Notify the listeners. - mHandler.post(() -> { - for (BatterySaverPolicyListener listener : listeners) { - listener.onBatterySaverPolicyChanged(this); - } - }); + maybeNotifyListenersOfPolicyChange(); } @GuardedBy("mLock") @@ -404,31 +450,63 @@ public class BatterySaverPolicy extends ContentObserver { @GuardedBy("mLock") private void updatePolicyDependenciesLocked() { - final Policy currPolicy = getCurrentPolicyLocked(); - // Update the effective vibration policy. - mDisableVibrationEffective = currPolicy.disableVibration - && !mAccessibilityEnabled; // Don't disable vibration when accessibility is on. + final Policy rawPolicy = getCurrentRawPolicyLocked(); + + final int locationMode; + if (mCarModeEnabled + && rawPolicy.locationMode != PowerManager.LOCATION_MODE_NO_CHANGE + && rawPolicy.locationMode != PowerManager.LOCATION_MODE_FOREGROUND_ONLY) { + // If car projection is enabled, ensure that navigation works. + locationMode = PowerManager.LOCATION_MODE_FOREGROUND_ONLY; + } else { + locationMode = rawPolicy.locationMode; + } + mEffectivePolicy = new Policy( + rawPolicy.adjustBrightnessFactor, + rawPolicy.advertiseIsEnabled, + rawPolicy.deferFullBackup, + rawPolicy.deferKeyValueBackup, + rawPolicy.disableAnimation, + rawPolicy.disableAod, + rawPolicy.disableLaunchBoost, + rawPolicy.disableOptionalSensors, + rawPolicy.disableSoundTrigger, + // Don't disable vibration when accessibility is on. + rawPolicy.disableVibration && !mAccessibilityEnabled, + rawPolicy.enableAdjustBrightness, + rawPolicy.enableDataSaver, + rawPolicy.enableFirewall, + // Don't force night mode when car projection is enabled. + rawPolicy.enableNightMode && !mCarModeEnabled, + rawPolicy.enableQuickDoze, + rawPolicy.filesForInteractive, + rawPolicy.filesForNoninteractive, + rawPolicy.forceAllAppsStandby, + rawPolicy.forceBackgroundCheck, + locationMode + ); + final StringBuilder sb = new StringBuilder(); - if (currPolicy.forceAllAppsStandby) sb.append("A"); - if (currPolicy.forceBackgroundCheck) sb.append("B"); + if (mEffectivePolicy.forceAllAppsStandby) sb.append("A"); + if (mEffectivePolicy.forceBackgroundCheck) sb.append("B"); - if (mDisableVibrationEffective) sb.append("v"); - if (currPolicy.disableAnimation) sb.append("a"); - if (currPolicy.disableSoundTrigger) sb.append("s"); - if (currPolicy.deferFullBackup) sb.append("F"); - if (currPolicy.deferKeyValueBackup) sb.append("K"); - if (currPolicy.enableFirewall) sb.append("f"); - if (currPolicy.enableDataSaver) sb.append("d"); - if (currPolicy.enableAdjustBrightness) sb.append("b"); + if (mEffectivePolicy.disableVibration) sb.append("v"); + if (mEffectivePolicy.disableAnimation) sb.append("a"); + if (mEffectivePolicy.disableSoundTrigger) sb.append("s"); + if (mEffectivePolicy.deferFullBackup) sb.append("F"); + if (mEffectivePolicy.deferKeyValueBackup) sb.append("K"); + if (mEffectivePolicy.enableFirewall) sb.append("f"); + if (mEffectivePolicy.enableDataSaver) sb.append("d"); + if (mEffectivePolicy.enableAdjustBrightness) sb.append("b"); - if (currPolicy.disableLaunchBoost) sb.append("l"); - if (currPolicy.disableOptionalSensors) sb.append("S"); - if (currPolicy.disableAod) sb.append("o"); - if (currPolicy.enableQuickDoze) sb.append("q"); + if (mEffectivePolicy.disableLaunchBoost) sb.append("l"); + if (mEffectivePolicy.disableOptionalSensors) sb.append("S"); + if (mEffectivePolicy.disableAod) sb.append("o"); + if (mEffectivePolicy.enableQuickDoze) sb.append("q"); - sb.append(currPolicy.locationMode); + sb.append(mEffectivePolicy.locationMode); mEventLogKeys = sb.toString(); } @@ -857,7 +935,7 @@ public class BatterySaverPolicy extends ContentObserver { return builder.setBatterySaverEnabled(currPolicy.disableSoundTrigger) .build(); case ServiceType.VIBRATION: - return builder.setBatterySaverEnabled(mDisableVibrationEffective) + return builder.setBatterySaverEnabled(currPolicy.disableVibration) .build(); case ServiceType.FORCE_ALL_APPS_STANDBY: return builder.setBatterySaverEnabled(currPolicy.forceAllAppsStandby) @@ -933,6 +1011,10 @@ public class BatterySaverPolicy extends ContentObserver { } private Policy getCurrentPolicyLocked() { + return mEffectivePolicy; + } + + private Policy getCurrentRawPolicyLocked() { switch (getPolicyLevelLocked()) { case POLICY_LEVEL_FULL: return mFullPolicy; @@ -994,11 +1076,13 @@ public class BatterySaverPolicy extends ContentObserver { pw.println(" value: " + mAdaptiveDeviceSpecificSettings); pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled); + pw.println(" mCarModeEnabled=" + mCarModeEnabled); pw.println(" mPolicyLevel=" + getPolicyLevelLocked()); dumpPolicyLocked(pw, " ", "full", mFullPolicy); dumpPolicyLocked(pw, " ", "default adaptive", mDefaultAdaptivePolicy); dumpPolicyLocked(pw, " ", "current adaptive", mAdaptivePolicy); + dumpPolicyLocked(pw, " ", "effective", mEffectivePolicy); } } @@ -1009,11 +1093,7 @@ public class BatterySaverPolicy extends ContentObserver { pw.print(indent); pw.println(" " + KEY_ADVERTISE_IS_ENABLED + "=" + p.advertiseIsEnabled); pw.print(indent); - pw.println(" " + KEY_VIBRATION_DISABLED + ":config=" + p.disableVibration); - // mDisableVibrationEffective is based on the currently selected policy - pw.print(indent); - pw.println(" " + KEY_VIBRATION_DISABLED + ":effective=" + (p.disableVibration - && !mAccessibilityEnabled)); + pw.println(" " + KEY_VIBRATION_DISABLED + "=" + p.disableVibration); pw.print(indent); pw.println(" " + KEY_ANIMATION_DISABLED + "=" + p.disableAnimation); pw.print(indent); @@ -1070,10 +1150,24 @@ public class BatterySaverPolicy extends ContentObserver { } @VisibleForTesting - public void setAccessibilityEnabledForTest(boolean enabled) { + void setAccessibilityEnabled(boolean enabled) { synchronized (mLock) { - mAccessibilityEnabled = enabled; - updatePolicyDependenciesLocked(); + if (mAccessibilityEnabled != enabled) { + mAccessibilityEnabled = enabled; + updatePolicyDependenciesLocked(); + maybeNotifyListenersOfPolicyChange(); + } + } + } + + @VisibleForTesting + void setCarModeEnabled(boolean enabled) { + synchronized (mLock) { + if (mCarModeEnabled != enabled) { + mCarModeEnabled = enabled; + updatePolicyDependenciesLocked(); + maybeNotifyListenersOfPolicyChange(); + } } } diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java index 7b96777b5987..885f561d2a19 100644 --- a/services/core/java/com/android/server/rollback/Rollback.java +++ b/services/core/java/com/android/server/rollback/Rollback.java @@ -159,13 +159,6 @@ class Rollback { @Nullable public final String mInstallerPackageName; /** - * This array holds all of the rollback tokens associated with package sessions included in - * this rollback. - */ - @GuardedBy("mLock") - private final IntArray mTokens = new IntArray(); - - /** * Session ids for all packages in the install. For multi-package sessions, this is the list * of child session ids. For normal sessions, this list is a single element with the normal * session id. @@ -769,26 +762,6 @@ class Rollback { } /** - * Adds a rollback token to be associated with this rollback. This may be used to - * identify which rollback should be removed in case {@link PackageManager} sends an - * {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} intent. - */ - void addToken(int token) { - synchronized (mLock) { - mTokens.add(token); - } - } - - /** - * Returns true if this rollback is associated with the provided {@code token}. - */ - boolean hasToken(int token) { - synchronized (mLock) { - return mTokens.indexOf(token) != -1; - } - } - - /** * Returns true if this rollback contains the provided {@code packageSessionId}. */ boolean containsSessionId(int packageSessionId) { diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index f9981d0d9c96..42fada19672e 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -20,7 +20,6 @@ import android.Manifest; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.AppOpsManager; import android.content.BroadcastReceiver; @@ -201,18 +200,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (Intent.ACTION_PACKAGE_ENABLE_ROLLBACK.equals(intent.getAction())) { int token = intent.getIntExtra( PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1); - int installFlags = intent.getIntExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_INSTALL_FLAGS, 0); - int user = intent.getIntExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER, 0); - - File newPackageCodePath = new File(intent.getData().getPath()); + int sessionId = intent.getIntExtra( + PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, -1); queueSleepIfNeeded(); getHandler().post(() -> { - boolean success = - enableRollback(installFlags, newPackageCodePath, user, token); + boolean success = enableRollback(sessionId); int ret = PackageManagerInternal.ENABLE_ROLLBACK_SUCCEEDED; if (!success) { ret = PackageManagerInternal.ENABLE_ROLLBACK_FAILED; @@ -238,19 +232,16 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_CANCEL_ENABLE_ROLLBACK.equals(intent.getAction())) { - int token = intent.getIntExtra( - PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1); + int sessionId = intent.getIntExtra( + PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID, -1); if (LOCAL_LOGV) { - Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK token=" + token); + Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK id=" + sessionId); } synchronized (mLock) { - for (int i = 0; i < mRollbacks.size(); ++i) { - Rollback rollback = mRollbacks.get(i); - if (rollback.hasToken(token) && rollback.isEnabling()) { - mRollbacks.remove(i); - rollback.delete(mAppDataRollbackHelper); - break; - } + Rollback rollback = getRollbackForSessionLocked(sessionId); + if (rollback != null && rollback.isEnabling()) { + mRollbacks.remove(rollback); + rollback.delete(mAppDataRollbackHelper); } } } @@ -684,24 +675,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return mHandlerThread.getThreadHandler(); } - // Returns true if <code>session</code> has installFlags and code path - // matching the installFlags and new package code path given to - // enableRollback. - @WorkerThread - private boolean sessionMatchesForEnableRollback(PackageInstaller.SessionInfo session, - int installFlags, File newPackageCodePath) { - if (session == null || session.resolvedBaseCodePath == null) { - return false; - } - - File packageCodePath = new File(session.resolvedBaseCodePath).getParentFile(); - if (newPackageCodePath.equals(packageCodePath) && installFlags == session.installFlags) { - return true; - } - - return false; - } - @AnyThread private Context getContextAsUser(UserHandle user) { try { @@ -716,58 +689,26 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * staged for install with rollback enabled. Called before the package has * been installed. * - * @param installFlags information about what is being installed. - * @param newPackageCodePath path to the package about to be installed. - * @param user the user that owns the install session to enable rollback on. - * @param token the distinct rollback token sent by package manager. + * @param sessionId the id of the install session * @return true if enabling the rollback succeeds, false otherwise. */ @WorkerThread - private boolean enableRollback( - int installFlags, File newPackageCodePath, @UserIdInt int user, int token) { + private boolean enableRollback(int sessionId) { if (LOCAL_LOGV) { - Slog.v(TAG, "enableRollback user=" + user + " token=" + token - + " path=" + newPackageCodePath.getAbsolutePath()); + Slog.v(TAG, "enableRollback sessionId=" + sessionId); } - // Find the session id associated with this install. - // TODO: It would be nice if package manager or package installer told - // us the session directly, rather than have to search for it - // ourselves. - - // getAllSessions only returns sessions for the associated user. - // Create a context with the right user so we can find the matching - // session. - final Context context = getContextAsUser(UserHandle.of(user)); - if (context == null) { - Slog.e(TAG, "Unable to create context for install session user."); + PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); + PackageInstaller.SessionInfo packageSession = installer.getSessionInfo(sessionId); + if (packageSession == null) { + Slog.e(TAG, "Unable to find session for enabled rollback."); return false; } - PackageInstaller.SessionInfo parentSession = null; - PackageInstaller.SessionInfo packageSession = null; - PackageInstaller installer = context.getPackageManager().getPackageInstaller(); - for (PackageInstaller.SessionInfo info : installer.getAllSessions()) { - if (info.isMultiPackage()) { - for (int childId : info.getChildSessionIds()) { - PackageInstaller.SessionInfo child = installer.getSessionInfo(childId); - if (sessionMatchesForEnableRollback(child, installFlags, newPackageCodePath)) { - // TODO: Check we only have one matching session? - parentSession = info; - packageSession = child; - break; - } - } - } else if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) { - // TODO: Check we only have one matching session? - parentSession = info; - packageSession = info; - break; - } - } - - if (parentSession == null || packageSession == null) { - Slog.e(TAG, "Unable to find session for enabled rollback."); + PackageInstaller.SessionInfo parentSession = packageSession.hasParentSessionId() + ? installer.getSessionInfo(packageSession.getParentSessionId()) : packageSession; + if (parentSession == null) { + Slog.e(TAG, "Unable to find parent session for enabled rollback."); return false; } @@ -804,7 +745,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { newRollback = createNewRollbackLocked(parentSession); } } - newRollback.addToken(token); return enableRollbackForPackageSession(newRollback, packageSession); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java index a641f06ac3ca..1d31285ed9c7 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java @@ -196,8 +196,8 @@ class ConversionUtil { hidlModel.header.type = aidl2hidlSoundModelType(aidlModel.type); hidlModel.header.uuid = aidl2hidlUuid(aidlModel.uuid); hidlModel.header.vendorUuid = aidl2hidlUuid(aidlModel.vendorUuid); - hidlModel.data = HidlMemoryUtil.byteArrayToHidlMemory(aidlModel.data, - "SoundTrigger SoundModel"); + hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(aidlModel.data, + aidlModel.dataSize); return hidlModel; } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java b/services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java new file mode 100644 index 000000000000..f9aa009c6e2a --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/Dumpable.java @@ -0,0 +1,32 @@ +/* + * 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.soundtrigger_middleware; + +import android.annotation.NonNull; + +import java.io.PrintWriter; + +/** + * An interface of an object that can generate a dump. + */ +interface Dumpable { + /** + * Generate a human-readable dump into the given writer. + * @param pw The writer. + */ + void dump(@NonNull PrintWriter pw); +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java new file mode 100644 index 000000000000..7f047f882122 --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java @@ -0,0 +1,249 @@ +/* + * 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.soundtrigger_middleware; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Map; + +/** + * A collection of pretty-print utilities for data objects. + */ +class ObjectPrinter { + /** Default maximum elements to print in a collection. */ + static public final int kDefaultMaxCollectionLength = 16; + + /** + * Simple version of {@link #print(Object, boolean, int)} that prints an object, without + * recursing into sub-objects. + * + * @param obj The object to print. + * @return A string representing the object. + */ + static String print(@Nullable Object obj) { + return print(obj, false, kDefaultMaxCollectionLength); + } + + /** + * Pretty-prints an object. + * + * @param obj The object to print. + * @param deep Whether to pretty-print sub-objects (if false, just prints them + * with {@link Object#toString()}). + * @param maxCollectionLength Whenever encountering collections, maximum number of elements to + * print. + * @return A string representing the object. + */ + static String print(@Nullable Object obj, boolean deep, int maxCollectionLength) { + StringBuilder builder = new StringBuilder(); + print(builder, obj, deep, maxCollectionLength); + return builder.toString(); + } + + /** + * This version is suitable for use inside a toString() override of an object, e.g.: + * <pre><code> + * class MyObject { + * ... + * @Override + * String toString() { + * return ObjectPrinter.printPublicFields(this, ...); + * } + * } + * </code></pre> + * + * @param obj The object to print. + * @param deep Whether to pretty-print sub-objects (if false, just prints them + * with {@link Object#toString()}). + * @param maxCollectionLength Whenever encountering collections, maximum number of elements to + * print. + */ + static String printPublicFields(@Nullable Object obj, boolean deep, int maxCollectionLength) { + StringBuilder builder = new StringBuilder(); + printPublicFields(builder, obj, deep, maxCollectionLength); + return builder.toString(); + } + + /** + * A version of {@link #print(Object, boolean, int)} that uses a {@link StringBuilder}. + * + * @param builder StringBuilder to print into. + * @param obj The object to print. + * @param deep Whether to pretty-print sub-objects (if false, just prints them + * with {@link Object#toString()}). + * @param maxCollectionLength Whenever encountering collections, maximum number of elements to + * print. + */ + static void print(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep, + int maxCollectionLength) { + try { + if (obj == null) { + builder.append("null"); + return; + } + if (obj instanceof Boolean) { + builder.append(obj.toString()); + return; + } + if (obj instanceof Number) { + builder.append(obj.toString()); + return; + } + if (obj instanceof Character) { + builder.append('\''); + builder.append(obj.toString()); + builder.append('\''); + return; + } + if (obj instanceof String) { + builder.append('"'); + builder.append(obj.toString()); + builder.append('"'); + return; + } + + Class cls = obj.getClass(); + + if (Collection.class.isAssignableFrom(cls)) { + Collection collection = (Collection) obj; + builder.append("[ "); + int length = collection.size(); + boolean isLong = false; + int i = 0; + for (Object child : collection) { + if (i > 0) { + builder.append(", "); + } + if (i >= maxCollectionLength) { + isLong = true; + break; + } + print(builder, child, deep, maxCollectionLength); + ++i; + } + if (isLong) { + builder.append("... (+"); + builder.append(length - maxCollectionLength); + builder.append(" entries)"); + } + builder.append(" ]"); + return; + } + + if (Map.class.isAssignableFrom(cls)) { + Map<?, ?> map = (Map<?, ?>) obj; + builder.append("< "); + int length = map.size(); + boolean isLong = false; + int i = 0; + for (Map.Entry<?, ?> child : map.entrySet()) { + if (i > 0) { + builder.append(", "); + } + if (i >= maxCollectionLength) { + isLong = true; + break; + } + print(builder, child.getKey(), deep, maxCollectionLength); + builder.append(": "); + print(builder, child.getValue(), deep, maxCollectionLength); + ++i; + } + if (isLong) { + builder.append("... (+"); + builder.append(length - maxCollectionLength); + builder.append(" entries)"); + } + builder.append(" >"); + return; + } + + if (cls.isArray()) { + builder.append("[ "); + int length = Array.getLength(obj); + boolean isLong = false; + for (int i = 0; i < length; ++i) { + if (i > 0) { + builder.append(", "); + } + if (i >= maxCollectionLength) { + isLong = true; + break; + } + print(builder, Array.get(obj, i), deep, maxCollectionLength); + } + if (isLong) { + builder.append("... (+"); + builder.append(length - maxCollectionLength); + builder.append(" entries)"); + } + builder.append(" ]"); + return; + } + + if (!deep) { + builder.append(obj.toString()); + return; + } + printPublicFields(builder, obj, deep, maxCollectionLength); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * A version of {@link #printPublicFields(Object, boolean, int)} that uses a {@link + * StringBuilder}. + * + * @param obj The object to print. + * @param deep Whether to pretty-print sub-objects (if false, just prints them + * with {@link Object#toString()}). + * @param maxCollectionLength Whenever encountering collections, maximum number of elements to + * print. + */ + static void printPublicFields(@NonNull StringBuilder builder, @Nullable Object obj, + boolean deep, + int maxCollectionLength) { + try { + Class cls = obj.getClass(); + builder.append("{ "); + + boolean first = true; + for (Field fld : cls.getDeclaredFields()) { + int mod = fld.getModifiers(); + if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.STATIC) == 0) { + if (first) { + first = false; + } else { + builder.append(", "); + } + builder.append(fld.getName()); + builder.append(": "); + print(builder, fld.get(obj), deep, maxCollectionLength); + } + } + builder.append(" }"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java new file mode 100644 index 000000000000..fa78cb0931c2 --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java @@ -0,0 +1,454 @@ +/* + * 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.soundtrigger_middleware; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.media.soundtrigger_middleware.ISoundTriggerCallback; +import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; +import android.media.soundtrigger_middleware.ISoundTriggerModule; +import android.media.soundtrigger_middleware.ModelParameterRange; +import android.media.soundtrigger_middleware.PhraseRecognitionEvent; +import android.media.soundtrigger_middleware.PhraseSoundModel; +import android.media.soundtrigger_middleware.RecognitionConfig; +import android.media.soundtrigger_middleware.RecognitionEvent; +import android.media.soundtrigger_middleware.SoundModel; +import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; +import android.os.Binder; +import android.os.IBinder; +import android.os.Parcelable; +import android.os.RemoteException; +import android.util.Log; + +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedList; + +/** + * An ISoundTriggerMiddlewareService decorator, which adds logging of all API calls (and + * callbacks). + * + * All API methods should follow this structure: + * <pre><code> + * @Override + * public @NonNull ReturnType someMethod(ArgType1 arg1, ArgType2 arg2) throws ExceptionType { + * try { + * ReturnType result = mDelegate.someMethod(arg1, arg2); + * logReturn("someMethod", result, arg1, arg2); + * return result; + * } catch (Exception e) { + * logException("someMethod", e, arg1, arg2); + * throw e; + * } + * } + * </code></pre> + * The actual handling of these events is then done inside of {@link #logReturnWithObject(Object, + * String, Object, Object[])}, {@link #logVoidReturnWithObject(Object, String, Object[])} and {@link + * #logExceptionWithObject(Object, String, Exception, Object[])}. + */ +public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareService, Dumpable { + private static final String TAG = "SoundTriggerMiddlewareLogging"; + private final @NonNull ISoundTriggerMiddlewareService mDelegate; + + public SoundTriggerMiddlewareLogging(@NonNull ISoundTriggerMiddlewareService delegate) { + mDelegate = delegate; + } + + @Override + public @NonNull SoundTriggerModuleDescriptor[] listModules() throws RemoteException { + try { + SoundTriggerModuleDescriptor[] result = mDelegate.listModules(); + logReturn("listModules", result); + return result; + } catch (Exception e) { + logException("listModules", e); + throw e; + } + } + + @Override + public @NonNull ISoundTriggerModule attach(int handle, ISoundTriggerCallback callback) + throws RemoteException { + try { + ISoundTriggerModule result = mDelegate.attach(handle, new CallbackLogging(callback)); + logReturn("attach", result, handle, callback); + return new ModuleLogging(result); + } catch (Exception e) { + logException("attach", e, handle, callback); + throw e; + } + } + + @Override + public void setExternalCaptureState(boolean active) throws RemoteException { + try { + mDelegate.setExternalCaptureState(active); + logVoidReturn("setExternalCaptureState", active); + } catch (Exception e) { + logException("setExternalCaptureState", e, active); + throw e; + } + } + + @Override public IBinder asBinder() { + throw new UnsupportedOperationException( + "This implementation is not inteded to be used directly with Binder."); + } + + // Override toString() in order to have the delegate's ID in it. + @Override + public String toString() { + return mDelegate.toString(); + } + + private void logException(String methodName, Exception ex, Object... args) { + logExceptionWithObject(this, methodName, ex, args); + } + + private void logReturn(String methodName, Object retVal, Object... args) { + logReturnWithObject(this, methodName, retVal, args); + } + + private void logVoidReturn(String methodName, Object... args) { + logVoidReturnWithObject(this, methodName, args); + } + + private class CallbackLogging implements ISoundTriggerCallback { + private final ISoundTriggerCallback mDelegate; + + private CallbackLogging(ISoundTriggerCallback delegate) { + mDelegate = delegate; + } + + @Override + public void onRecognition(int modelHandle, RecognitionEvent event) throws RemoteException { + try { + mDelegate.onRecognition(modelHandle, event); + logVoidReturn("onRecognition", modelHandle, event); + } catch (Exception e) { + logException("onRecognition", e, modelHandle, event); + throw e; + } + } + + @Override + public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event) + throws RemoteException { + try { + mDelegate.onPhraseRecognition(modelHandle, event); + logVoidReturn("onPhraseRecognition", modelHandle, event); + } catch (Exception e) { + logException("onPhraseRecognition", e, modelHandle, event); + throw e; + } + } + + @Override + public void onRecognitionAvailabilityChange(boolean available) throws RemoteException { + try { + mDelegate.onRecognitionAvailabilityChange(available); + logVoidReturn("onRecognitionAvailabilityChange", available); + } catch (Exception e) { + logException("onRecognitionAvailabilityChange", e, available); + throw e; + } + } + + @Override + public void onModuleDied() throws RemoteException { + try { + mDelegate.onModuleDied(); + logVoidReturn("onModuleDied"); + } catch (Exception e) { + logException("onModuleDied", e); + throw e; + } + } + + private void logException(String methodName, Exception ex, Object... args) { + logExceptionWithObject(this, methodName, ex, args); + } + + private void logVoidReturn(String methodName, Object... args) { + logVoidReturnWithObject(this, methodName, args); + } + + @Override + public IBinder asBinder() { + return mDelegate.asBinder(); + } + + // Override toString() in order to have the delegate's ID in it. + @Override + public String toString() { + return mDelegate.toString(); + } + } + + private class ModuleLogging implements ISoundTriggerModule { + private final ISoundTriggerModule mDelegate; + + private ModuleLogging(ISoundTriggerModule delegate) { + mDelegate = delegate; + } + + @Override + public int loadModel(SoundModel model) throws RemoteException { + try { + int result = mDelegate.loadModel(model); + logReturn("loadModel", result, model); + return result; + } catch (Exception e) { + logException("loadModel", e, model); + throw e; + } + } + + @Override + public int loadPhraseModel(PhraseSoundModel model) throws RemoteException { + try { + int result = mDelegate.loadPhraseModel(model); + logReturn("loadPhraseModel", result, model); + return result; + } catch (Exception e) { + logException("loadPhraseModel", e, model); + throw e; + } + } + + @Override + public void unloadModel(int modelHandle) throws RemoteException { + try { + mDelegate.unloadModel(modelHandle); + logVoidReturn("unloadModel", modelHandle); + } catch (Exception e) { + logException("unloadModel", e, modelHandle); + throw e; + } + } + + @Override + public void startRecognition(int modelHandle, RecognitionConfig config) + throws RemoteException { + try { + mDelegate.startRecognition(modelHandle, config); + logVoidReturn("startRecognition", modelHandle, config); + } catch (Exception e) { + logException("startRecognition", e, modelHandle, config); + throw e; + } + } + + @Override + public void stopRecognition(int modelHandle) throws RemoteException { + try { + mDelegate.stopRecognition(modelHandle); + logVoidReturn("stopRecognition", modelHandle); + } catch (Exception e) { + logException("stopRecognition", e, modelHandle); + throw e; + } + } + + @Override + public void forceRecognitionEvent(int modelHandle) throws RemoteException { + try { + mDelegate.forceRecognitionEvent(modelHandle); + logVoidReturn("forceRecognitionEvent", modelHandle); + } catch (Exception e) { + logException("forceRecognitionEvent", e, modelHandle); + throw e; + } + } + + @Override + public void setModelParameter(int modelHandle, int modelParam, int value) + throws RemoteException { + try { + mDelegate.setModelParameter(modelHandle, modelParam, value); + logVoidReturn("setModelParameter", modelHandle, modelParam, value); + } catch (Exception e) { + logException("setModelParameter", e, modelHandle, modelParam, value); + throw e; + } + } + + @Override + public int getModelParameter(int modelHandle, int modelParam) throws RemoteException { + try { + int result = mDelegate.getModelParameter(modelHandle, modelParam); + logReturn("getModelParameter", result, modelHandle, modelParam); + return result; + } catch (Exception e) { + logException("getModelParameter", e, modelHandle, modelParam); + throw e; + } + } + + @Override + public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) + throws RemoteException { + try { + ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle, + modelParam); + logReturn("queryModelParameterSupport", result, modelHandle, modelParam); + return result; + } catch (Exception e) { + logException("queryModelParameterSupport", e, modelHandle, modelParam); + throw e; + } + } + + @Override + public void detach() throws RemoteException { + try { + mDelegate.detach(); + logVoidReturn("detach"); + } catch (Exception e) { + logException("detach", e); + throw e; + } + } + + @Override + public IBinder asBinder() { + return mDelegate.asBinder(); + } + + // Override toString() in order to have the delegate's ID in it. + @Override + public String toString() { + return mDelegate.toString(); + } + + private void logException(String methodName, Exception ex, Object... args) { + logExceptionWithObject(this, methodName, ex, args); + } + + private void logReturn(String methodName, Object retVal, Object... args) { + logReturnWithObject(this, methodName, retVal, args); + } + + private void logVoidReturn(String methodName, Object... args) { + logVoidReturnWithObject(this, methodName, args); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Actual logging logic below. + private static final int NUM_EVENTS_TO_DUMP = 64; + private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss:SSS"); + private final @NonNull LinkedList<Event> mLastEvents = new LinkedList<>(); + + static private class Event { + public final long timestamp = System.currentTimeMillis(); + public final String message; + + private Event(String message) { + this.message = message; + } + } + + private static String printArgs(@NonNull Object[] args) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < args.length; ++i) { + if (i > 0) { + result.append(", "); + } + printObject(result, args[i]); + } + return result.toString(); + } + + private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) { + if (obj instanceof Parcelable) { + ObjectPrinter.print(builder, obj, true, 16); + } else { + builder.append(obj.toString()); + } + } + + private static String printObject(@Nullable Object obj) { + StringBuilder builder = new StringBuilder(); + printObject(builder, obj); + return builder.toString(); + } + + private void logReturnWithObject(@NonNull Object object, String methodName, + @Nullable Object retVal, + @NonNull Object[] args) { + final String message = String.format("%s[this=%s, caller=%d/%d](%s) -> %s", methodName, + object, + Binder.getCallingUid(), Binder.getCallingPid(), + printArgs(args), + printObject(retVal)); + Log.i(TAG, message); + appendMessage(message); + } + + private void logVoidReturnWithObject(@NonNull Object object, @NonNull String methodName, + @NonNull Object[] args) { + final String message = String.format("%s[this=%s, caller=%d/%d](%s)", methodName, + object, + Binder.getCallingUid(), Binder.getCallingPid(), + printArgs(args)); + Log.i(TAG, message); + appendMessage(message); + } + + private void logExceptionWithObject(@NonNull Object object, @NonNull String methodName, + @NonNull Exception ex, + Object[] args) { + final String message = String.format("%s[this=%s, caller=%d/%d](%s) threw", methodName, + object, + Binder.getCallingUid(), Binder.getCallingPid(), + printArgs(args)); + Log.e(TAG, message, ex); + appendMessage(message + " " + ex.toString()); + } + + private void appendMessage(@NonNull String message) { + Event event = new Event(message); + synchronized (mLastEvents) { + if (mLastEvents.size() > NUM_EVENTS_TO_DUMP) { + mLastEvents.remove(); + } + mLastEvents.add(event); + } + } + + @Override public void dump(PrintWriter pw) { + pw.println(); + pw.println("========================================="); + pw.println("Last events"); + pw.println("========================================="); + synchronized (mLastEvents) { + for (Event event : mLastEvents) { + pw.print(DATE_FORMAT.format(new Date(event.timestamp))); + pw.print('\t'); + pw.println(event.message); + } + } + pw.println(); + + if (mDelegate instanceof Dumpable) { + ((Dumpable) mDelegate).dump(pw); + } + } +} diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java index 1ed97becb776..0d8fc76e1bd2 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java @@ -16,91 +16,40 @@ package com.android.server.soundtrigger_middleware; -import android.Manifest; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.Context; -import android.content.PermissionChecker; import android.hardware.soundtrigger.V2_0.ISoundTriggerHw; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.ModelParameterRange; -import android.media.soundtrigger_middleware.PhraseRecognitionEvent; import android.media.soundtrigger_middleware.PhraseSoundModel; import android.media.soundtrigger_middleware.RecognitionConfig; -import android.media.soundtrigger_middleware.RecognitionEvent; -import android.media.soundtrigger_middleware.RecognitionStatus; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; -import android.media.soundtrigger_middleware.Status; import android.os.RemoteException; -import android.os.ServiceSpecificException; import android.util.Log; -import com.android.internal.util.Preconditions; import com.android.server.SystemService; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Objects; -import java.util.Set; /** * This is a wrapper around an {@link ISoundTriggerMiddlewareService} implementation, which exposes - * it as a Binder service and enforces permissions and correct usage by the client, as well as makes - * sure that exceptions representing a server malfunction do not get sent to the client. + * it as a Binder service. * <p> - * This is intended to extract the non-business logic out of the underlying implementation and thus - * make it easier to maintain each one of those separate aspects. A design trade-off is being made - * here, in that this class would need to essentially eavesdrop on all the client-server - * communication and retain all state known to the client, while the client doesn't necessarily care - * about all of it, and while the server has its own representation of this information. However, - * in this case, this is a small amount of data, and the benefits in code elegance seem worth it. - * There is also some additional cost in employing a simplistic locking mechanism here, but - * following the same line of reasoning, the benefits in code simplicity outweigh it. + * This is intended to facilitate a pattern of decorating the core implementation (business logic) + * of the interface with every decorator implementing a different aspect of the service, such as + * validation and logging. This class acts as the top-level decorator, which also adds the binder- + * related functionality (hence, it extends ISoundTriggerMiddlewareService.Stub as rather than + * implements ISoundTriggerMiddlewareService), and does the same thing for child interfaces + * returned. * <p> - * Every public method in this class, overriding an interface method, must follow the following - * pattern: - * <code><pre> - * @Override public T method(S arg) { - * // Permission check. - * checkPermissions(); - * // Input validation. - * ValidationUtil.validateS(arg); - * synchronized (this) { - * // State validation. - * if (...state is not valid for this call...) { - * throw new IllegalStateException("State is invalid because..."); - * } - * // From here on, every exception isn't client's fault. - * try { - * T result = mDelegate.method(arg); - * // Update state.; - * ... - * return result; - * } catch (Exception e) { - * throw handleException(e); - * } - * } - * } - * </pre></code> - * Following this patterns ensures a consistent and rigorous handling of all aspects associated - * with client-server separation. - * <p> - * <b>Exception handling approach:</b><br> - * We make sure all client faults (permissions, argument and state validation) happen first, and - * would throw {@link SecurityException}, {@link IllegalArgumentException}/ - * {@link NullPointerException} or {@link - * IllegalStateException}, respectively. All those exceptions are treated specially by Binder and - * will get sent back to the client.<br> - * Once this is done, any subsequent fault is considered a server fault. Only {@link - * RecoverableException}s thrown by the implementation are special-cased: they would get sent back - * to the caller as a {@link ServiceSpecificException}, which is the behavior of Binder. Any other - * exception gets wrapped with a {@link InternalServerError}, which is specifically chosen as a type - * that <b>does NOT</b> get forwarded by binder. Those exceptions would be handled by a high-level - * exception handler on the server side, typically resulting in rebooting the server. + * The inner class {@link Lifecycle} acts as both a factory, composing the various aspect-decorators + * to create a full-featured implementation, as well as as an entry-point for presenting this + * implementation as a system service. * <p> * <b>Exposing this service as a System Service:</b><br> * Insert this line into {@link com.android.server.SystemServer}: @@ -113,637 +62,129 @@ import java.util.Set; public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareService.Stub { static private final String TAG = "SoundTriggerMiddlewareService"; + @NonNull private final ISoundTriggerMiddlewareService mDelegate; - private final Context mContext; - private Set<Integer> mModuleHandles; /** * Constructor for internal use only. Could be exposed for testing purposes in the future. * Users should access this class via {@link Lifecycle}. */ - private SoundTriggerMiddlewareService( - @NonNull ISoundTriggerMiddlewareService delegate, @NonNull Context context) { - mDelegate = delegate; - mContext = context; - } - - /** - * Generic exception handling for exceptions thrown by the underlying implementation. - * - * Would throw any {@link RecoverableException} as a {@link ServiceSpecificException} (passed - * by Binder to the caller) and <i>any other</i> exception as {@link InternalServerError} - * (<b>not</b> passed by Binder to the caller). - * <p> - * Typical usage: - * <code><pre> - * try { - * ... Do server operations ... - * } catch (Exception e) { - * throw handleException(e); - * } - * </pre></code> - */ - private static @NonNull - RuntimeException handleException(@NonNull Exception e) { - if (e instanceof RecoverableException) { - throw new ServiceSpecificException(((RecoverableException) e).errorCode, - e.getMessage()); - } - throw new InternalServerError(e); + private SoundTriggerMiddlewareService(@NonNull ISoundTriggerMiddlewareService delegate) { + mDelegate = Objects.requireNonNull(delegate); } @Override public @NonNull - SoundTriggerModuleDescriptor[] listModules() { - // Permission check. - checkPermissions(); - // Input validation (always valid). - - synchronized (this) { - // State validation (always valid). - - // From here on, every exception isn't client's fault. - try { - SoundTriggerModuleDescriptor[] result = mDelegate.listModules(); - mModuleHandles = new HashSet<>(result.length); - for (SoundTriggerModuleDescriptor desc : result) { - mModuleHandles.add(desc.handle); - } - return result; - } catch (Exception e) { - throw handleException(e); - } - } + SoundTriggerModuleDescriptor[] listModules() throws RemoteException { + return mDelegate.listModules(); } @Override public @NonNull - ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback) { - // Permission check. - checkPermissions(); - // Input validation. - Objects.requireNonNull(callback); - Objects.requireNonNull(callback.asBinder()); - - synchronized (this) { - // State validation. - if (mModuleHandles == null) { - throw new IllegalStateException( - "Client must call listModules() prior to attaching."); - } - if (!mModuleHandles.contains(handle)) { - throw new IllegalArgumentException("Invalid handle: " + handle); - } - - // From here on, every exception isn't client's fault. - try { - ModuleService moduleService = new ModuleService(callback); - moduleService.attach(mDelegate.attach(handle, moduleService)); - return moduleService; - } catch (Exception e) { - throw handleException(e); - } - } + ISoundTriggerModule attach(int handle, @NonNull ISoundTriggerCallback callback) + throws RemoteException { + return new ModuleService(mDelegate.attach(handle, callback)); } @Override - public void setExternalCaptureState(boolean active) { - // Permission check. - checkPreemptPermissions(); - // Input validation (always valid). - - synchronized (this) { - // State validation (always valid). - - // From here on, every exception isn't client's fault. - try { - mDelegate.setExternalCaptureState(active); - } catch (Exception e) { - throw handleException(e); - } - } - } - - /** - * Throws a {@link SecurityException} if caller permanently doesn't have the given permission, - * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if - * caller temporarily doesn't have the right permissions to use this service. - */ - private void checkPermissions() { - enforcePermission(Manifest.permission.RECORD_AUDIO); - enforcePermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD); - } - - /** - * Throws a {@link SecurityException} if caller permanently doesn't have the given permission, - * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if - * caller temporarily doesn't have the right permissions to preempt active sound trigger - * sessions. - */ - private void checkPreemptPermissions() { - enforcePermission(Manifest.permission.PREEMPT_SOUND_TRIGGER); - } - - /** - * Throws a {@link SecurityException} if caller permanently doesn't have the given permission, - * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if - * caller temporarily doesn't have the given permission. - * - * @param permission The permission to check. - */ - private void enforcePermission(String permission) { - final int status = PermissionChecker.checkCallingOrSelfPermissionForPreflight(mContext, - permission); - switch (status) { - case PermissionChecker.PERMISSION_GRANTED: - return; - case PermissionChecker.PERMISSION_HARD_DENIED: - throw new SecurityException( - String.format("Caller must have the %s permission.", permission)); - case PermissionChecker.PERMISSION_SOFT_DENIED: - throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED, - String.format("Caller must have the %s permission.", permission)); - default: - throw new InternalServerError( - new RuntimeException("Unexpected perimission check result.")); - } - } - - /** State of a sound model. */ - static class ModelState { - /** Activity state of a sound model. */ - enum Activity { - /** Model is loaded, recognition is inactive. */ - LOADED, - /** Model is loaded, recognition is active. */ - ACTIVE - } - - /** Activity state. */ - Activity activityState = Activity.LOADED; - - /** - * A map of known parameter support. A missing key means we don't know yet whether the - * parameter is supported. A null value means it is known to not be supported. A non-null - * value indicates the valid value range. - */ - private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>(); - - /** - * Check that the given parameter is known to be supported for this model. - * - * @param modelParam The parameter key. - */ - void checkSupported(int modelParam) { - if (!parameterSupport.containsKey(modelParam)) { - throw new IllegalStateException("Parameter has not been checked for support."); - } - ModelParameterRange range = parameterSupport.get(modelParam); - if (range == null) { - throw new IllegalArgumentException("Paramater is not supported."); - } - } - - /** - * Check that the given parameter is known to be supported for this model and that the given - * value is a valid value for it. - * - * @param modelParam The parameter key. - * @param value The value. - */ - void checkSupported(int modelParam, int value) { - if (!parameterSupport.containsKey(modelParam)) { - throw new IllegalStateException("Parameter has not been checked for support."); - } - ModelParameterRange range = parameterSupport.get(modelParam); - if (range == null) { - throw new IllegalArgumentException("Paramater is not supported."); - } - Preconditions.checkArgumentInRange(value, range.minInclusive, range.maxInclusive, - "value"); - } - - /** - * Update support state for the given parameter for this model. - * - * @param modelParam The parameter key. - * @param range The parameter value range, or null if not supported. - */ - void updateParameterSupport(int modelParam, @Nullable ModelParameterRange range) { - parameterSupport.put(modelParam, range); - } + public void setExternalCaptureState(boolean active) throws RemoteException { + mDelegate.setExternalCaptureState(active); } - /** - * Entry-point to this module: exposes the module as a {@link SystemService}. - */ - public static final class Lifecycle extends SystemService { - public Lifecycle(Context context) { - super(context); - } - - @Override - public void onStart() { - HalFactory[] factories = new HalFactory[]{() -> { - try { - Log.d(TAG, "Connecting to default ISoundTriggerHw"); - return ISoundTriggerHw.getService(true); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - }}; - - publishBinderService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE, - new SoundTriggerMiddlewareService( - new SoundTriggerMiddlewareImpl(factories, - new AudioSessionProviderImpl()), - getContext())); + @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { + if (mDelegate instanceof Dumpable) { + ((Dumpable) mDelegate).dump(fout); } } - /** - * A wrapper around an {@link ISoundTriggerModule} implementation, to address the same aspects - * mentioned in {@link SoundTriggerModule} above. This class follows the same conventions. - */ - private class ModuleService extends ISoundTriggerModule.Stub implements ISoundTriggerCallback, - DeathRecipient { - private final ISoundTriggerCallback mCallback; - private ISoundTriggerModule mDelegate; - private @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>(); - - ModuleService(@NonNull ISoundTriggerCallback callback) { - mCallback = callback; - try { - mCallback.asBinder().linkToDeath(this, 0); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } + private final static class ModuleService extends ISoundTriggerModule.Stub { + private final ISoundTriggerModule mDelegate; - void attach(@NonNull ISoundTriggerModule delegate) { + private ModuleService(ISoundTriggerModule delegate) { mDelegate = delegate; } @Override - public int loadModel(@NonNull SoundModel model) { - // Permission check. - checkPermissions(); - // Input validation. - ValidationUtil.validateGenericModel(model); - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - - // From here on, every exception isn't client's fault. - try { - int handle = mDelegate.loadModel(model); - mLoadedModels.put(handle, new ModelState()); - return handle; - } catch (Exception e) { - throw handleException(e); - } - } + public int loadModel(SoundModel model) throws RemoteException { + return mDelegate.loadModel(model); } @Override - public int loadPhraseModel(@NonNull PhraseSoundModel model) { - // Permission check. - checkPermissions(); - // Input validation. - ValidationUtil.validatePhraseModel(model); - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - - // From here on, every exception isn't client's fault. - try { - int handle = mDelegate.loadPhraseModel(model); - mLoadedModels.put(handle, new ModelState()); - return handle; - } catch (Exception e) { - throw handleException(e); - } - } + public int loadPhraseModel(PhraseSoundModel model) throws RemoteException { + return mDelegate.loadPhraseModel(model); } @Override - public void unloadModel(int modelHandle) { - // Permission check. - checkPermissions(); - // Input validation (always valid). - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState == null) { - throw new IllegalStateException("Invalid handle: " + modelHandle); - } - if (modelState.activityState != ModelState.Activity.LOADED) { - throw new IllegalStateException("Model with handle: " + modelHandle - + " has invalid state for unloading: " + modelState.activityState); - } - - // From here on, every exception isn't client's fault. - try { - mDelegate.unloadModel(modelHandle); - mLoadedModels.remove(modelHandle); - } catch (Exception e) { - throw handleException(e); - } - } + public void unloadModel(int modelHandle) throws RemoteException { + mDelegate.unloadModel(modelHandle); + ; } @Override - public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) { - // Permission check. - checkPermissions(); - // Input validation. - ValidationUtil.validateRecognitionConfig(config); - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState == null) { - throw new IllegalStateException("Invalid handle: " + modelHandle); - } - if (modelState.activityState != ModelState.Activity.LOADED) { - throw new IllegalStateException("Model with handle: " + modelHandle - + " has invalid state for starting recognition: " - + modelState.activityState); - } - - // From here on, every exception isn't client's fault. - try { - mDelegate.startRecognition(modelHandle, config); - modelState.activityState = ModelState.Activity.ACTIVE; - } catch (Exception e) { - throw handleException(e); - } - } + public void startRecognition(int modelHandle, RecognitionConfig config) + throws RemoteException { + mDelegate.startRecognition(modelHandle, config); } @Override - public void stopRecognition(int modelHandle) { - // Permission check. - checkPermissions(); - // Input validation (always valid). - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState == null) { - throw new IllegalStateException("Invalid handle: " + modelHandle); - } - // stopRecognition is idempotent - no need to check model state. - - // From here on, every exception isn't client's fault. - try { - mDelegate.stopRecognition(modelHandle); - modelState.activityState = ModelState.Activity.LOADED; - } catch (Exception e) { - throw handleException(e); - } - } + public void stopRecognition(int modelHandle) throws RemoteException { + mDelegate.stopRecognition(modelHandle); } @Override - public void forceRecognitionEvent(int modelHandle) { - // Permission check. - checkPermissions(); - // Input validation (always valid). - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState == null) { - throw new IllegalStateException("Invalid handle: " + modelHandle); - } - // forceRecognitionEvent is idempotent - no need to check model state. - - // From here on, every exception isn't client's fault. - try { - mDelegate.forceRecognitionEvent(modelHandle); - } catch (Exception e) { - throw handleException(e); - } - } + public void forceRecognitionEvent(int modelHandle) throws RemoteException { + mDelegate.forceRecognitionEvent(modelHandle); } @Override - public void setModelParameter(int modelHandle, int modelParam, int value) { - // Permission check. - checkPermissions(); - // Input validation. - ValidationUtil.validateModelParameter(modelParam); - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState == null) { - throw new IllegalStateException("Invalid handle: " + modelHandle); - } - modelState.checkSupported(modelParam, value); - - // From here on, every exception isn't client's fault. - try { - mDelegate.setModelParameter(modelHandle, modelParam, value); - } catch (Exception e) { - throw handleException(e); - } - } + public void setModelParameter(int modelHandle, int modelParam, int value) + throws RemoteException { + mDelegate.setModelParameter(modelHandle, modelParam, value); } @Override - public int getModelParameter(int modelHandle, int modelParam) { - // Permission check. - checkPermissions(); - // Input validation. - ValidationUtil.validateModelParameter(modelParam); - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState == null) { - throw new IllegalStateException("Invalid handle: " + modelHandle); - } - modelState.checkSupported(modelParam); - - // From here on, every exception isn't client's fault. - try { - return mDelegate.getModelParameter(modelHandle, modelParam); - } catch (Exception e) { - throw handleException(e); - } - } + public int getModelParameter(int modelHandle, int modelParam) throws RemoteException { + return mDelegate.getModelParameter(modelHandle, modelParam); } @Override - @Nullable - public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) { - // Permission check. - checkPermissions(); - // Input validation. - ValidationUtil.validateModelParameter(modelParam); - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has been detached."); - } - ModelState modelState = mLoadedModels.get(modelHandle); - if (modelState == null) { - throw new IllegalStateException("Invalid handle: " + modelHandle); - } - - // From here on, every exception isn't client's fault. - try { - ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle, - modelParam); - modelState.updateParameterSupport(modelParam, result); - return result; - } catch (Exception e) { - throw handleException(e); - } - } + public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) + throws RemoteException { + return mDelegate.queryModelParameterSupport(modelHandle, modelParam); } @Override - public void detach() { - // Permission check. - checkPermissions(); - // Input validation (always valid). - - synchronized (this) { - // State validation. - if (mDelegate == null) { - throw new IllegalStateException("Module has already been detached."); - } - if (!mLoadedModels.isEmpty()) { - throw new IllegalStateException("Cannot detach while models are loaded."); - } - - // From here on, every exception isn't client's fault. - try { - detachInternal(); - } catch (Exception e) { - throw handleException(e); - } - } - } - - private void detachInternal() { - try { - mDelegate.detach(); - mDelegate = null; - mCallback.asBinder().unlinkToDeath(this, 0); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - - //////////////////////////////////////////////////////////////////////////////////////////// - // Callbacks - - @Override - public void onRecognition(int modelHandle, @NonNull RecognitionEvent event) { - synchronized (this) { - if (event.status != RecognitionStatus.FORCED) { - mLoadedModels.get(modelHandle).activityState = ModelState.Activity.LOADED; - } - try { - mCallback.onRecognition(modelHandle, event); - } catch (RemoteException e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback exception.", e); - } - } - } - - @Override - public void onPhraseRecognition(int modelHandle, @NonNull PhraseRecognitionEvent event) { - synchronized (this) { - if (event.common.status != RecognitionStatus.FORCED) { - mLoadedModels.get(modelHandle).activityState = ModelState.Activity.LOADED; - } - try { - mCallback.onPhraseRecognition(modelHandle, event); - } catch (RemoteException e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback exception.", e); - } - } + public void detach() throws RemoteException { + mDelegate.detach(); } + } - @Override - public void onRecognitionAvailabilityChange(boolean available) { - synchronized (this) { - try { - mCallback.onRecognitionAvailabilityChange(available); - } catch (RemoteException e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback exception.", e); - } - } + /** + * Entry-point to this module: exposes the module as a {@link SystemService}. + */ + public static final class Lifecycle extends SystemService { + public Lifecycle(Context context) { + super(context); } @Override - public void onModuleDied() { - synchronized (this) { + public void onStart() { + HalFactory[] factories = new HalFactory[]{() -> { try { - mCallback.onModuleDied(); + Log.d(TAG, "Connecting to default ISoundTriggerHw"); + return ISoundTriggerHw.getService(true); } catch (RemoteException e) { - // Dead client will be handled by binderDied() - no need to handle here. - // In any case, client callbacks are considered best effort. - Log.e(TAG, "Client callback exception.", e); + throw e.rethrowAsRuntimeException(); } - } - } + }}; - @Override - public void binderDied() { - // This is called whenever our client process dies. - synchronized (this) { - try { - // Gracefully stop all active recognitions and unload the models. - for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { - if (entry.getValue().activityState == ModelState.Activity.ACTIVE) { - mDelegate.stopRecognition(entry.getKey()); - } - mDelegate.unloadModel(entry.getKey()); - } - // Detach. - detachInternal(); - } catch (Exception e) { - throw handleException(e); - } - } + publishBinderService(Context.SOUND_TRIGGER_MIDDLEWARE_SERVICE, + new SoundTriggerMiddlewareService( + new SoundTriggerMiddlewareLogging( + new SoundTriggerMiddlewareValidation( + new SoundTriggerMiddlewareImpl(factories, + new AudioSessionProviderImpl()), + getContext())))); } } } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java new file mode 100644 index 000000000000..c45f37dfdbd8 --- /dev/null +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -0,0 +1,784 @@ +/* + * 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.soundtrigger_middleware; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.content.PermissionChecker; +import android.media.soundtrigger_middleware.ISoundTriggerCallback; +import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; +import android.media.soundtrigger_middleware.ISoundTriggerModule; +import android.media.soundtrigger_middleware.ModelParameterRange; +import android.media.soundtrigger_middleware.PhraseRecognitionEvent; +import android.media.soundtrigger_middleware.PhraseSoundModel; +import android.media.soundtrigger_middleware.RecognitionConfig; +import android.media.soundtrigger_middleware.RecognitionEvent; +import android.media.soundtrigger_middleware.RecognitionStatus; +import android.media.soundtrigger_middleware.SoundModel; +import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; +import android.media.soundtrigger_middleware.Status; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.util.Log; + +import com.android.internal.util.Preconditions; + +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * This is a decorator of an {@link ISoundTriggerMiddlewareService}, which enforces permissions and + * correct usage by the client, as well as makes sure that exceptions representing a server + * malfunction do not get sent to the client. + * <p> + * This is intended to extract the non-business logic out of the underlying implementation and thus + * make it easier to maintain each one of those separate aspects. A design trade-off is being made + * here, in that this class would need to essentially eavesdrop on all the client-server + * communication and retain all state known to the client, while the client doesn't necessarily care + * about all of it, and while the server has its own representation of this information. However, + * in this case, this is a small amount of data, and the benefits in code elegance seem worth it. + * There is also some additional cost in employing a simplistic locking mechanism here, but + * following the same line of reasoning, the benefits in code simplicity outweigh it. + * <p> + * Every public method in this class, overriding an interface method, must follow the following + * pattern: + * <code><pre> + * @Override public T method(S arg) { + * // Permission check. + * checkPermissions(); + * // Input validation. + * ValidationUtil.validateS(arg); + * synchronized (this) { + * // State validation. + * if (...state is not valid for this call...) { + * throw new IllegalStateException("State is invalid because..."); + * } + * // From here on, every exception isn't client's fault. + * try { + * T result = mDelegate.method(arg); + * // Update state.; + * ... + * return result; + * } catch (Exception e) { + * throw handleException(e); + * } + * } + * } + * </pre></code> + * Following this patterns ensures a consistent and rigorous handling of all aspects associated + * with client-server separation. + * <p> + * <b>Exception handling approach:</b><br> + * We make sure all client faults (permissions, argument and state validation) happen first, and + * would throw {@link SecurityException}, {@link IllegalArgumentException}/ + * {@link NullPointerException} or {@link + * IllegalStateException}, respectively. All those exceptions are treated specially by Binder and + * will get sent back to the client.<br> + * Once this is done, any subsequent fault is considered a server fault. Only {@link + * RecoverableException}s thrown by the implementation are special-cased: they would get sent back + * to the caller as a {@link ServiceSpecificException}, which is the behavior of Binder. Any other + * exception gets wrapped with a {@link InternalServerError}, which is specifically chosen as a type + * that <b>does NOT</b> get forwarded by binder. Those exceptions would be handled by a high-level + * exception handler on the server side, typically resulting in rebooting the server. + * + * {@hide} + */ +public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddlewareService, Dumpable { + private static final String TAG = "SoundTriggerMiddlewareValidation"; + + private final @NonNull ISoundTriggerMiddlewareService mDelegate; + private final @NonNull Context mContext; + private Map<Integer, Set<ModuleService>> mModules; + + public SoundTriggerMiddlewareValidation( + @NonNull ISoundTriggerMiddlewareService delegate, @NonNull Context context) { + mDelegate = delegate; + mContext = context; + } + + /** + * Generic exception handling for exceptions thrown by the underlying implementation. + * + * Would throw any {@link RecoverableException} as a {@link ServiceSpecificException} (passed + * by Binder to the caller) and <i>any other</i> exception as {@link InternalServerError} + * (<b>not</b> passed by Binder to the caller). + * <p> + * Typical usage: + * <code><pre> + * try { + * ... Do server operations ... + * } catch (Exception e) { + * throw handleException(e); + * } + * </pre></code> + */ + static @NonNull + RuntimeException handleException(@NonNull Exception e) { + if (e instanceof RecoverableException) { + throw new ServiceSpecificException(((RecoverableException) e).errorCode, + e.getMessage()); + } + throw new InternalServerError(e); + } + + @Override + public @NonNull + SoundTriggerModuleDescriptor[] listModules() { + // Permission check. + checkPermissions(); + // Input validation (always valid). + + synchronized (this) { + // State validation (always valid). + + // From here on, every exception isn't client's fault. + try { + SoundTriggerModuleDescriptor[] result = mDelegate.listModules(); + mModules = new HashMap<>(result.length); + for (SoundTriggerModuleDescriptor desc : result) { + mModules.put(desc.handle, new HashSet<>()); + } + return result; + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public @NonNull ISoundTriggerModule attach(int handle, + @NonNull ISoundTriggerCallback callback) { + // Permission check. + checkPermissions(); + // Input validation. + Objects.requireNonNull(callback); + Objects.requireNonNull(callback.asBinder()); + + synchronized (this) { + // State validation. + if (mModules == null) { + throw new IllegalStateException( + "Client must call listModules() prior to attaching."); + } + if (!mModules.containsKey(handle)) { + throw new IllegalArgumentException("Invalid handle: " + handle); + } + + // From here on, every exception isn't client's fault. + try { + ModuleService moduleService = + new ModuleService(handle, callback); + moduleService.attach(mDelegate.attach(handle, moduleService)); + return moduleService; + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public void setExternalCaptureState(boolean active) { + // Permission check. + checkPreemptPermissions(); + // Input validation (always valid). + + synchronized (this) { + // State validation (always valid). + + // From here on, every exception isn't client's fault. + try { + mDelegate.setExternalCaptureState(active); + } catch (Exception e) { + throw handleException(e); + } + } + } + + // Override toString() in order to have the delegate's ID in it. + @Override + public String toString() { + return mDelegate.toString(); + } + + /** + * Throws a {@link SecurityException} if caller permanently doesn't have the given permission, + * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if + * caller temporarily doesn't have the right permissions to use this service. + */ + void checkPermissions() { + enforcePermission(Manifest.permission.RECORD_AUDIO); + enforcePermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD); + } + + /** + * Throws a {@link SecurityException} if caller permanently doesn't have the given permission, + * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if + * caller temporarily doesn't have the right permissions to preempt active sound trigger + * sessions. + */ + void checkPreemptPermissions() { + enforcePermission(Manifest.permission.PREEMPT_SOUND_TRIGGER); + } + + /** + * Throws a {@link SecurityException} if caller permanently doesn't have the given permission, + * or a {@link ServiceSpecificException} with a {@link Status#TEMPORARY_PERMISSION_DENIED} if + * caller temporarily doesn't have the given permission. + * + * @param permission The permission to check. + */ + void enforcePermission(String permission) { + final int status = PermissionChecker.checkCallingOrSelfPermissionForPreflight(mContext, + permission); + switch (status) { + case PermissionChecker.PERMISSION_GRANTED: + return; + case PermissionChecker.PERMISSION_HARD_DENIED: + throw new SecurityException( + String.format("Caller must have the %s permission.", permission)); + case PermissionChecker.PERMISSION_SOFT_DENIED: + throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED, + String.format("Caller must have the %s permission.", permission)); + default: + throw new InternalServerError( + new RuntimeException("Unexpected perimission check result.")); + } + } + + @Override + public IBinder asBinder() { + throw new UnsupportedOperationException( + "This implementation is not inteded to be used directly with Binder."); + } + + @Override public void dump(PrintWriter pw) { + synchronized (this) { + if (mModules != null) { + for (int handle : mModules.keySet()) { + pw.println("========================================="); + pw.printf("Active sessions for module %d", handle); + pw.println(); + pw.println("========================================="); + for (ModuleService session : mModules.get(handle)) { + session.dump(pw); + } + } + } + } + pw.println(); + + if (mDelegate instanceof Dumpable) { + ((Dumpable) mDelegate).dump(pw); + } + + } + + /** State of a sound model. */ + static class ModelState { + /** Activity state of a sound model. */ + enum Activity { + /** Model is loaded, recognition is inactive. */ + LOADED, + /** Model is loaded, recognition is active. */ + ACTIVE + } + + /** Activity state. */ + Activity activityState = Activity.LOADED; + + /** + * A map of known parameter support. A missing key means we don't know yet whether the + * parameter is supported. A null value means it is known to not be supported. A non-null + * value indicates the valid value range. + */ + private Map<Integer, ModelParameterRange> parameterSupport = new HashMap<>(); + + /** + * Check that the given parameter is known to be supported for this model. + * + * @param modelParam The parameter key. + */ + void checkSupported(int modelParam) { + if (!parameterSupport.containsKey(modelParam)) { + throw new IllegalStateException("Parameter has not been checked for support."); + } + ModelParameterRange range = parameterSupport.get(modelParam); + if (range == null) { + throw new IllegalArgumentException("Paramater is not supported."); + } + } + + /** + * Check that the given parameter is known to be supported for this model and that the given + * value is a valid value for it. + * + * @param modelParam The parameter key. + * @param value The value. + */ + void checkSupported(int modelParam, int value) { + if (!parameterSupport.containsKey(modelParam)) { + throw new IllegalStateException("Parameter has not been checked for support."); + } + ModelParameterRange range = parameterSupport.get(modelParam); + if (range == null) { + throw new IllegalArgumentException("Paramater is not supported."); + } + Preconditions.checkArgumentInRange(value, range.minInclusive, range.maxInclusive, + "value"); + } + + /** + * Update support state for the given parameter for this model. + * + * @param modelParam The parameter key. + * @param range The parameter value range, or null if not supported. + */ + void updateParameterSupport(int modelParam, @Nullable ModelParameterRange range) { + parameterSupport.put(modelParam, range); + } + } + + /** + * A wrapper around an {@link ISoundTriggerModule} implementation, to address the same aspects + * mentioned in {@link SoundTriggerModule} above. This class follows the same conventions. + */ + private class ModuleService extends ISoundTriggerModule.Stub implements ISoundTriggerCallback, + IBinder.DeathRecipient { + private final ISoundTriggerCallback mCallback; + private ISoundTriggerModule mDelegate; + private @NonNull Map<Integer, ModelState> mLoadedModels = new HashMap<>(); + private final int mHandle; + + ModuleService(int handle, @NonNull ISoundTriggerCallback callback) { + mCallback = callback; + mHandle = handle; + try { + mCallback.asBinder().linkToDeath(null, 0); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + void attach(@NonNull ISoundTriggerModule delegate) { + mDelegate = delegate; + mModules.get(mHandle).add(this); + } + + @Override + public int loadModel(@NonNull SoundModel model) { + // Permission check. + checkPermissions(); + // Input validation. + ValidationUtil.validateGenericModel(model); + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + + // From here on, every exception isn't client's fault. + try { + int handle = mDelegate.loadModel(model); + mLoadedModels.put(handle, new ModelState()); + return handle; + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public int loadPhraseModel(@NonNull PhraseSoundModel model) { + // Permission check. + checkPermissions(); + // Input validation. + ValidationUtil.validatePhraseModel(model); + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + + // From here on, every exception isn't client's fault. + try { + int handle = mDelegate.loadPhraseModel(model); + mLoadedModels.put(handle, new ModelState()); + return handle; + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public void unloadModel(int modelHandle) { + // Permission check. + checkPermissions(); + // Input validation (always valid). + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + ModelState modelState = mLoadedModels.get( + modelHandle); + if (modelState == null) { + throw new IllegalStateException("Invalid handle: " + modelHandle); + } + if (modelState.activityState + != ModelState.Activity.LOADED) { + throw new IllegalStateException("Model with handle: " + modelHandle + + " has invalid state for unloading: " + modelState.activityState); + } + + // From here on, every exception isn't client's fault. + try { + mDelegate.unloadModel(modelHandle); + mLoadedModels.remove(modelHandle); + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) { + // Permission check. + checkPermissions(); + // Input validation. + ValidationUtil.validateRecognitionConfig(config); + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + ModelState modelState = mLoadedModels.get( + modelHandle); + if (modelState == null) { + throw new IllegalStateException("Invalid handle: " + modelHandle); + } + if (modelState.activityState + != ModelState.Activity.LOADED) { + throw new IllegalStateException("Model with handle: " + modelHandle + + " has invalid state for starting recognition: " + + modelState.activityState); + } + + // From here on, every exception isn't client's fault. + try { + mDelegate.startRecognition(modelHandle, config); + modelState.activityState = + ModelState.Activity.ACTIVE; + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public void stopRecognition(int modelHandle) { + // Permission check. + checkPermissions(); + // Input validation (always valid). + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + ModelState modelState = mLoadedModels.get( + modelHandle); + if (modelState == null) { + throw new IllegalStateException("Invalid handle: " + modelHandle); + } + // stopRecognition is idempotent - no need to check model state. + + // From here on, every exception isn't client's fault. + try { + mDelegate.stopRecognition(modelHandle); + modelState.activityState = + ModelState.Activity.LOADED; + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public void forceRecognitionEvent(int modelHandle) { + // Permission check. + checkPermissions(); + // Input validation (always valid). + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + ModelState modelState = mLoadedModels.get( + modelHandle); + if (modelState == null) { + throw new IllegalStateException("Invalid handle: " + modelHandle); + } + // forceRecognitionEvent is idempotent - no need to check model state. + + // From here on, every exception isn't client's fault. + try { + mDelegate.forceRecognitionEvent(modelHandle); + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public void setModelParameter(int modelHandle, int modelParam, int value) { + // Permission check. + checkPermissions(); + // Input validation. + ValidationUtil.validateModelParameter(modelParam); + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + ModelState modelState = mLoadedModels.get( + modelHandle); + if (modelState == null) { + throw new IllegalStateException("Invalid handle: " + modelHandle); + } + modelState.checkSupported(modelParam, value); + + // From here on, every exception isn't client's fault. + try { + mDelegate.setModelParameter(modelHandle, modelParam, value); + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public int getModelParameter(int modelHandle, int modelParam) { + // Permission check. + checkPermissions(); + // Input validation. + ValidationUtil.validateModelParameter(modelParam); + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + ModelState modelState = mLoadedModels.get( + modelHandle); + if (modelState == null) { + throw new IllegalStateException("Invalid handle: " + modelHandle); + } + modelState.checkSupported(modelParam); + + // From here on, every exception isn't client's fault. + try { + return mDelegate.getModelParameter(modelHandle, modelParam); + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + @Nullable + public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) { + // Permission check. + checkPermissions(); + // Input validation. + ValidationUtil.validateModelParameter(modelParam); + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has been detached."); + } + ModelState modelState = mLoadedModels.get( + modelHandle); + if (modelState == null) { + throw new IllegalStateException("Invalid handle: " + modelHandle); + } + + // From here on, every exception isn't client's fault. + try { + ModelParameterRange result = mDelegate.queryModelParameterSupport(modelHandle, + modelParam); + modelState.updateParameterSupport(modelParam, result); + return result; + } catch (Exception e) { + throw handleException(e); + } + } + } + + @Override + public void detach() { + // Permission check. + checkPermissions(); + // Input validation (always valid). + + synchronized (SoundTriggerMiddlewareValidation.this) { + // State validation. + if (mDelegate == null) { + throw new IllegalStateException("Module has already been detached."); + } + if (!mLoadedModels.isEmpty()) { + throw new IllegalStateException("Cannot detach while models are loaded."); + } + + // From here on, every exception isn't client's fault. + try { + detachInternal(); + } catch (Exception e) { + throw handleException(e); + } + } + } + + // Override toString() in order to have the delegate's ID in it. + @Override + public String toString() { + return mDelegate.toString(); + } + + private void detachInternal() { + try { + mDelegate.detach(); + mDelegate = null; + mCallback.asBinder().unlinkToDeath(null, 0); + mModules.get(mHandle).remove(this); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + void dump(PrintWriter pw) { + pw.printf("Loaded models for session %s (handle, active)", toString()); + pw.println(); + pw.println("-------------------------------"); + for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { + pw.print(entry.getKey()); + pw.print('\t'); + pw.print(entry.getValue().activityState.name()); + pw.println(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////// + // Callbacks + + @Override + public void onRecognition(int modelHandle, @NonNull RecognitionEvent event) { + synchronized (SoundTriggerMiddlewareValidation.this) { + if (event.status != RecognitionStatus.FORCED) { + mLoadedModels.get(modelHandle).activityState = + ModelState.Activity.LOADED; + } + try { + mCallback.onRecognition(modelHandle, event); + } catch (RemoteException e) { + // Dead client will be handled by binderDied() - no need to handle here. + // In any case, client callbacks are considered best effort. + Log.e(TAG, "Client callback exception.", e); + } + } + } + + @Override + public void onPhraseRecognition(int modelHandle, @NonNull PhraseRecognitionEvent event) { + synchronized (SoundTriggerMiddlewareValidation.this) { + if (event.common.status != RecognitionStatus.FORCED) { + mLoadedModels.get(modelHandle).activityState = + ModelState.Activity.LOADED; + } + try { + mCallback.onPhraseRecognition(modelHandle, event); + } catch (RemoteException e) { + // Dead client will be handled by binderDied() - no need to handle here. + // In any case, client callbacks are considered best effort. + Log.e(TAG, "Client callback exception.", e); + } + } + } + + @Override + public void onRecognitionAvailabilityChange(boolean available) { + synchronized (SoundTriggerMiddlewareValidation.this) { + try { + mCallback.onRecognitionAvailabilityChange(available); + } catch (RemoteException e) { + // Dead client will be handled by binderDied() - no need to handle here. + // In any case, client callbacks are considered best effort. + Log.e(TAG, "Client callback exception.", e); + } + } + } + + @Override + public void onModuleDied() { + synchronized (SoundTriggerMiddlewareValidation.this) { + try { + mCallback.onModuleDied(); + } catch (RemoteException e) { + // Dead client will be handled by binderDied() - no need to handle here. + // In any case, client callbacks are considered best effort. + Log.e(TAG, "Client callback exception.", e); + } + } + } + + @Override + public void binderDied() { + // This is called whenever our client process dies. + synchronized (SoundTriggerMiddlewareValidation.this) { + try { + // Gracefully stop all active recognitions and unload the models. + for (Map.Entry<Integer, ModelState> entry : + mLoadedModels.entrySet()) { + if (entry.getValue().activityState + == ModelState.Activity.ACTIVE) { + mDelegate.stopRecognition(entry.getKey()); + } + mDelegate.unloadModel(entry.getKey()); + } + // Detach. + detachInternal(); + } catch (Exception e) { + throw handleException(e); + } + } + } + } +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java index aa1558ebfc70..d6390184e3bd 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java @@ -123,7 +123,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { */ synchronized @NonNull ISoundTriggerModule attach(@NonNull ISoundTriggerCallback callback) { - Log.d(TAG, "attach()"); Session session = new Session(callback); mActiveSessions.add(session); return session; @@ -149,8 +148,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { * @param active true iff external capture is active. */ synchronized void setExternalCaptureState(boolean active) { - Log.d(TAG, String.format("setExternalCaptureState(active=%b)", active)); - if (mProperties.concurrentCapture) { // If we support concurrent capture, we don't care about any of this. return; @@ -235,7 +232,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public void detach() { - Log.d(TAG, "detach()"); synchronized (SoundTriggerModule.this) { if (mCallback == null) { return; @@ -247,8 +243,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public int loadModel(@NonNull SoundModel model) { - Log.d(TAG, String.format("loadModel(model=%s)", model)); - // We must do this outside the lock, to avoid possible deadlocks with the remote process // that provides the audio sessions, which may also be calling into us. SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession = @@ -276,8 +270,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public int loadPhraseModel(@NonNull PhraseSoundModel model) { - Log.d(TAG, String.format("loadPhraseModel(model=%s)", model)); - // We must do this outside the lock, to avoid possible deadlocks with the remote process // that provides the audio sessions, which may also be calling into us. SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession = @@ -306,10 +298,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public void unloadModel(int modelHandle) { - Log.d(TAG, String.format("unloadModel(handle=%d)", modelHandle)); - int sessionId; - synchronized (SoundTriggerModule.this) { checkValid(); sessionId = mLoadedModels.get(modelHandle).unload(); @@ -323,8 +312,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public void startRecognition(int modelHandle, @NonNull RecognitionConfig config) { - Log.d(TAG, - String.format("startRecognition(handle=%d, config=%s)", modelHandle, config)); synchronized (SoundTriggerModule.this) { checkValid(); mLoadedModels.get(modelHandle).startRecognition(config); @@ -333,7 +320,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public void stopRecognition(int modelHandle) { - Log.d(TAG, String.format("stopRecognition(handle=%d)", modelHandle)); synchronized (SoundTriggerModule.this) { mLoadedModels.get(modelHandle).stopRecognition(); } @@ -341,7 +327,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public void forceRecognitionEvent(int modelHandle) { - Log.d(TAG, String.format("forceRecognitionEvent(handle=%d)", modelHandle)); synchronized (SoundTriggerModule.this) { checkValid(); mLoadedModels.get(modelHandle).forceRecognitionEvent(); @@ -350,9 +335,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public void setModelParameter(int modelHandle, int modelParam, int value) { - Log.d(TAG, - String.format("setModelParameter(handle=%d, param=%d, value=%d)", modelHandle, - modelParam, value)); synchronized (SoundTriggerModule.this) { checkValid(); mLoadedModels.get(modelHandle).setParameter(modelParam, value); @@ -361,8 +343,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override public int getModelParameter(int modelHandle, int modelParam) { - Log.d(TAG, String.format("getModelParameter(handle=%d, param=%d)", modelHandle, - modelParam)); synchronized (SoundTriggerModule.this) { checkValid(); return mLoadedModels.get(modelHandle).getParameter(modelParam); @@ -372,8 +352,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @Override @Nullable public ModelParameterRange queryModelParameterSupport(int modelHandle, int modelParam) { - Log.d(TAG, String.format("queryModelParameterSupport(handle=%d, param=%d)", modelHandle, - modelParam)); synchronized (SoundTriggerModule.this) { checkValid(); return mLoadedModels.get(modelHandle).queryModelParameterSupport(modelParam); @@ -584,8 +562,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { public void recognitionCallback( @NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent, int cookie) { - Log.d(TAG, String.format("recognitionCallback_2_1(event=%s, cookie=%d)", - recognitionEvent, cookie)); synchronized (SoundTriggerModule.this) { android.media.soundtrigger_middleware.RecognitionEvent aidlEvent = ConversionUtil.hidl2aidlRecognitionEvent(recognitionEvent); @@ -608,8 +584,6 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { public void phraseRecognitionCallback( @NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent, int cookie) { - Log.d(TAG, String.format("phraseRecognitionCallback_2_1(event=%s, cookie=%d)", - phraseRecognitionEvent, cookie)); synchronized (SoundTriggerModule.this) { android.media.soundtrigger_middleware.PhraseRecognitionEvent aidlEvent = ConversionUtil.hidl2aidlPhraseRecognitionEvent(phraseRecognitionEvent); diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 3f8f6bfed9ca..e426574fb9b7 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -436,8 +436,7 @@ public class StatsPullAtomService extends SystemService { mStoragedUidIoStatsReader = new StoragedUidIoStatsReader(); // Initialize PROC_STATS - // TODO (b/148402814): Change this directory to stats_pull. - mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_companion"); + mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_pull"); // Disables throttler on CPU time readers. mCpuUidUserSysTimeReader = new KernelCpuUidUserSysTimeReader(false); diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 5f5cd3c46117..2394bafc09de 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -1437,7 +1437,8 @@ public class TrustManagerService extends SystemService { if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) { refreshAgentList(getSendingUserId()); updateDevicePolicyFeatures(); - } else if (Intent.ACTION_USER_ADDED.equals(action)) { + } else if (Intent.ACTION_USER_ADDED.equals(action) || Intent.ACTION_USER_STARTED.equals( + action)) { int userId = getUserId(intent); if (userId > 0) { maybeEnableFactoryTrustAgents(mLockPatternUtils, userId); @@ -1478,6 +1479,7 @@ public class TrustManagerService extends SystemService { filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_STARTED); context.registerReceiverAsUser(this, UserHandle.ALL, filter, diff --git a/services/core/java/com/android/server/utils/quota/QuotaTracker.java b/services/core/java/com/android/server/utils/quota/QuotaTracker.java index a8cf9f6c0ec4..115b5c8d4010 100644 --- a/services/core/java/com/android/server/utils/quota/QuotaTracker.java +++ b/services/core/java/com/android/server/utils/quota/QuotaTracker.java @@ -552,6 +552,7 @@ abstract class QuotaTracker { mTriggerTimeElapsed = nextTriggerTimeElapsed; } } else { + cancelAlarm(this); mTriggerTimeElapsed = 0; } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 2115f7ccfe98..6eb3c0fb06fb 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1173,6 +1173,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } }; + private Runnable mTryToRebindRunnable = () -> { + tryToRebind(); + }; + WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) { mInfo = info; mWallpaper = wallpaper; @@ -1279,7 +1283,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub saveSettingsLocked(mWallpaper.userId); } FgThread.getHandler().removeCallbacks(mResetRunnable); - mContext.getMainThreadHandler().removeCallbacks(this::tryToRebind); + mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable); } } } @@ -1337,7 +1341,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub < WALLPAPER_RECONNECT_TIMEOUT_MS) { // Bind fail without timeout, schedule rebind Slog.w(TAG, "Rebind fail! Try again later"); - mContext.getMainThreadHandler().postDelayed(this::tryToRebind, 1000); + mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1000); } else { // Timeout Slog.w(TAG, "Reverting to built-in wallpaper!"); diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 68a71881b898..4fea36c040f9 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -275,8 +275,9 @@ class ActivityMetricsLogger { } /** @return {@code true} if the activity matches a launched activity in this transition. */ - boolean contains(ActivityRecord r) { - return r == mLastLaunchedActivity || mPendingDrawActivities.contains(r); + boolean contains(WindowContainer wc) { + final ActivityRecord r = AppTransitionController.getAppFromContainer(wc); + return r != null && (r == mLastLaunchedActivity || mPendingDrawActivities.contains(r)); } /** Called when the activity is drawn or won't be drawn. */ @@ -435,10 +436,10 @@ class ActivityMetricsLogger { /** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */ @Nullable - private TransitionInfo getActiveTransitionInfo(ActivityRecord r) { + private TransitionInfo getActiveTransitionInfo(WindowContainer wc) { for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) { final TransitionInfo info = mTransitionInfoList.get(i); - if (info.contains(r)) { + if (info.contains(wc)) { return info; } } @@ -623,19 +624,19 @@ class ActivityMetricsLogger { * @param activityToReason A map from activity to a reason integer, which must be on of * ActivityTaskManagerInternal.APP_TRANSITION_* reasons. */ - void notifyTransitionStarting(ArrayMap<ActivityRecord, Integer> activityToReason) { + void notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason) { if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting"); final long timestampNs = SystemClock.elapsedRealtimeNanos(); for (int index = activityToReason.size() - 1; index >= 0; index--) { - final ActivityRecord r = activityToReason.keyAt(index); - final TransitionInfo info = getActiveTransitionInfo(r); + final WindowContainer wc = activityToReason.keyAt(index); + final TransitionInfo info = getActiveTransitionInfo(wc); if (info == null || info.mLoggedTransitionStarting) { // Ignore any subsequent notifyTransitionStarting. continue; } if (DEBUG_METRICS) { - Slog.i(TAG, "notifyTransitionStarting activity=" + r + " info=" + info); + Slog.i(TAG, "notifyTransitionStarting activity=" + wc + " info=" + info); } info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d715ed408d51..76bc36620c85 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -40,7 +40,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.activityTypeToString; @@ -106,7 +105,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; -import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; import static android.view.WindowManager.TRANSIT_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_UNSET; @@ -284,7 +282,6 @@ import android.view.DisplayInfo; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IApplicationToken; import android.view.InputApplicationHandle; -import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; @@ -577,12 +574,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ private boolean mCurrentLaunchCanTurnScreenOn = true; - /** - * This leash is used to "freeze" the app surface in place after the state change, but before - * the animation is ready to start. - */ - private SurfaceControl mTransitChangeLeash = null; - /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */ private boolean mLastSurfaceShowing = true; @@ -1329,15 +1320,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mDisplayContent.executeAppTransition(); } - if (prevDc.mChangingApps.remove(this)) { - // This gets called *after* the ActivityRecord has been reparented to the new display. - // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN), - // so this token is now "frozen" while waiting for the animation to start on prevDc - // (which will be cancelled since the window is no-longer a child). However, since this - // is no longer a child of prevDc, this won't be notified of the cancelled animation, - // so we need to cancel the change transition here. - clearChangeLeash(getPendingTransaction(), true /* cancel */); - } prevDc.mClosingApps.remove(this); if (prevDc.mFocusedApp == this) { @@ -3092,7 +3074,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A commitVisibility(false /* visible */, true /* performLayout */); getDisplayContent().mOpeningApps.remove(this); - getDisplayContent().mChangingApps.remove(this); + getDisplayContent().mChangingContainers.remove(this); getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this); mWmService.mTaskSnapshotController.onAppRemoved(this); mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this); @@ -3995,13 +3977,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A appToken, visible, appTransition, isVisible(), mVisibleRequested, Debug.getCallers(6)); + onChildVisibilityRequested(visible); + final DisplayContent displayContent = getDisplayContent(); displayContent.mOpeningApps.remove(this); displayContent.mClosingApps.remove(this); - if (isInChangeTransition()) { - clearChangeLeash(getPendingTransaction(), true /* cancel */); - } - displayContent.mChangingApps.remove(this); waitingToShow = false; mVisibleRequested = visible; mLastDeferHidingClient = deferHidingClient; @@ -4198,13 +4178,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final DisplayContent displayContent = getDisplayContent(); if (!displayContent.mClosingApps.contains(this) && !displayContent.mOpeningApps.contains(this)) { - // The token is not closing nor opening, so even if there is an animation set, that - // doesn't mean that it goes through the normal app transition cycle so we have - // to inform the docked controller about visibility change. - // TODO(multi-display): notify docked divider on all displays where visibility was - // affected. - displayContent.getDockedDividerController().notifyAppVisibilityChanged(); - // Take the screenshot before possibly hiding the WSA, otherwise the screenshot // will not be taken. mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible); @@ -5805,11 +5778,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation; } - @Override - boolean isChangingAppTransition() { - return task != null ? task.isChangingAppTransition() : super.isChangingAppTransition(); - } - /** * Creates a layer to apply crop to an animation. */ @@ -5830,84 +5798,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this, endDeferFinishCallback); } - private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) { - if (mWmService.mDisableTransitionAnimation - || !isVisible() - || getDisplayContent().mAppTransition.isTransitionSet() - || getSurfaceControl() == null) { - return false; - } - // Only do an animation into and out-of freeform mode for now. Other mode - // transition animations are currently handled by system-ui. - return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM); - } - @Override boolean isWaitingForTransitionStart() { final DisplayContent dc = getDisplayContent(); return dc != null && dc.mAppTransition.isTransitionSet() && (dc.mOpeningApps.contains(this) || dc.mClosingApps.contains(this) - || dc.mChangingApps.contains(this)); - } - - /** - * Initializes a change transition. Because the app is visible already, there is a small period - * of time where the user can see the app content/window update before the transition starts. - * To prevent this, we immediately take a snapshot and place the app/snapshot into a leash which - * "freezes" the location/crop until the transition starts. - * <p> - * Here's a walk-through of the process: - * 1. Create a temporary leash ("interim-change-leash") and reparent the app to it. - * 2. Set the temporary leash's position/crop to the current state. - * 3. Create a snapshot and place that at the top of the leash to cover up content changes. - * 4. Once the transition is ready, it will reparent the app to the animation leash. - * 5. Detach the interim-change-leash. - */ - private void initializeChangeTransition(Rect startBounds) { - mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE, - false /* alwaysKeepCurrent */, 0, false /* forceOverride */); - mDisplayContent.mChangingApps.add(this); - mTransitStartRect.set(startBounds); - - final SurfaceControl.Builder builder = makeAnimationLeash() - .setParent(getAnimationLeashParent()) - .setName(getSurfaceControl() + " - interim-change-leash"); - mTransitChangeLeash = builder.build(); - Transaction t = getPendingTransaction(); - t.setWindowCrop(mTransitChangeLeash, startBounds.width(), startBounds.height()); - t.setPosition(mTransitChangeLeash, startBounds.left, startBounds.top); - t.show(mTransitChangeLeash); - t.reparent(getSurfaceControl(), mTransitChangeLeash); - onAnimationLeashCreated(t, mTransitChangeLeash); - - // Skip creating snapshot if this transition is controlled by a remote animator which - // doesn't need it. - ArraySet<Integer> activityTypes = new ArraySet<>(); - activityTypes.add(getActivityType()); - RemoteAnimationAdapter adapter = - mDisplayContent.mAppTransitionController.getRemoteAnimationOverride( - this, TRANSIT_TASK_CHANGE_WINDOWING_MODE, activityTypes); - if (adapter != null && !adapter.getChangeNeedsSnapshot()) { - return; - } - - if (mThumbnail == null && task != null && !hasCommittedReparentToAnimationLeash()) { - SurfaceControl.ScreenshotGraphicBuffer snapshot = - mWmService.mTaskSnapshotController.createTaskSnapshot( - task, 1 /* scaleFraction */); - if (snapshot != null) { - mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory, t, this, - snapshot.getGraphicBuffer(), true /* relative */); - } - } + || dc.mChangingContainers.contains(this)); } - @Override - public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { + private int getAnimationLayer() { // The leash is parented to the animation layer. We need to preserve the z-order by using // the prefix order index, but we boost if necessary. - int layer = 0; + int layer; if (!inPinnedWindowingMode()) { layer = getPrefixOrderIndex(); } else { @@ -5920,21 +5823,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (mNeedsZBoost) { layer += Z_BOOST_BASE; } - if (!mNeedsAnimationBoundsLayer) { - t.setLayer(leash, layer); - } - - final DisplayContent dc = getDisplayContent(); - dc.assignStackOrdering(); + return layer; + } - if (leash == mTransitChangeLeash) { - // This is a temporary state so skip any animation notifications - return; - } else if (mTransitChangeLeash != null) { - // unparent mTransitChangeLeash for clean-up - clearChangeLeash(t, false /* cancel */); - } + @Override + public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { + t.setLayer(leash, getAnimationLayer()); + getDisplayContent().assignStackOrdering(); + } + @Override + public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) { if (mAnimatingActivityRegistry != null) { mAnimatingActivityRegistry.notifyStarting(this); } @@ -5962,7 +5861,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // surface size has already same as the animating container. t.setWindowCrop(mAnimationBoundsLayer, mTmpRect); } - t.setLayer(mAnimationBoundsLayer, layer); + t.setLayer(leash, 0); + t.setLayer(mAnimationBoundsLayer, getAnimationLayer()); // Reparent leash to animation bounds layer. t.reparent(leash, mAnimationBoundsLayer); @@ -5994,10 +5894,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return mLastSurfaceShowing; } - boolean isInChangeTransition() { - return mTransitChangeLeash != null || AppTransition.isChangeTransit(mTransit); - } - void attachThumbnailAnimation() { if (!isAnimating(PARENTS)) { return; @@ -6134,31 +6030,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } - /** - * @param cancel {@code true} if clearing the leash due to cancelling instead of transferring - * to another leash. - */ - private void clearChangeLeash(Transaction t, boolean cancel) { - if (mTransitChangeLeash == null) { - return; - } - if (cancel) { - clearThumbnail(); - SurfaceControl sc = getSurfaceControl(); - SurfaceControl parentSc = getParentSurfaceControl(); - // Don't reparent if surface is getting destroyed - if (parentSc != null && sc != null) { - t.reparent(sc, getParentSurfaceControl()); - } - } - t.hide(mTransitChangeLeash); - t.remove(mTransitChangeLeash); - mTransitChangeLeash = null; - if (cancel) { - onAnimationLeashLost(t); - } - } - void clearAnimatingFlags() { boolean wallpaperMightChange = false; for (int i = mChildren.size() - 1; i >= 0; i--) { @@ -6174,7 +6045,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void cancelAnimation() { cancelAnimationOnly(); clearThumbnail(); - clearChangeLeash(getPendingTransaction(), true /* cancel */); + mSurfaceFreezer.unfreeze(getPendingTransaction()); } /** @@ -6219,6 +6090,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mRemoteAnimationDefinition = null; } + @Override RemoteAnimationDefinition getRemoteAnimationDefinition() { return mRemoteAnimationDefinition; } @@ -6679,8 +6551,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } } - final int prevWinMode = getWindowingMode(); - mTmpPrevBounds.set(getBounds()); super.onConfigurationChanged(newParentConfig); if (shouldUseSizeCompatMode()) { @@ -6705,12 +6575,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - final int newWinMode = getWindowingMode(); - if ((prevWinMode != newWinMode) && (mDisplayContent != null) - && shouldStartChangeTransition(prevWinMode, newWinMode)) { - initializeChangeTransition(mTmpPrevBounds); - } - // Configuration's equality doesn't consider seq so if only seq number changes in resolved // override configuration. Therefore ConfigurationContainer doesn't change merged override // configuration, but it's used to push configuration changes so explicitly update that. @@ -7595,6 +7459,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + @Override void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(HASH_CODE, System.identityHashCode(this)); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index ff890ff13ee3..598389b1ba2b 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -17,8 +17,6 @@ package com.android.server.wm; import static android.app.ActivityTaskManager.INVALID_TASK_ID; -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; @@ -39,16 +37,10 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; -import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.view.Display.INVALID_DISPLAY; -import static android.view.WindowManager.DOCKED_BOTTOM; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_RIGHT; -import static android.view.WindowManager.DOCKED_TOP; import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; @@ -98,13 +90,8 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; -import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.TaskProto.ACTIVITIES; import static com.android.server.wm.TaskProto.ACTIVITY_TYPE; -import static com.android.server.wm.TaskProto.ADJUSTED_BOUNDS; -import static com.android.server.wm.TaskProto.ADJUSTED_FOR_IME; -import static com.android.server.wm.TaskProto.ADJUST_DIVIDER_AMOUNT; -import static com.android.server.wm.TaskProto.ADJUST_IME_AMOUNT; import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS; import static com.android.server.wm.TaskProto.BOUNDS; import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER; @@ -113,7 +100,6 @@ import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS; import static com.android.server.wm.TaskProto.DISPLAY_ID; import static com.android.server.wm.TaskProto.FILLS_PARENT; import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS; -import static com.android.server.wm.TaskProto.MINIMIZE_AMOUNT; import static com.android.server.wm.TaskProto.MIN_HEIGHT; import static com.android.server.wm.TaskProto.MIN_WIDTH; import static com.android.server.wm.TaskProto.ORIG_ACTIVITY; @@ -168,7 +154,6 @@ import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.Display; -import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.ITaskOrganizer; import android.view.SurfaceControl; @@ -177,8 +162,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.os.logging.MetricsLoggerWrapper; -import com.android.internal.policy.DividerSnapAlgorithm; -import com.android.internal.policy.DockedDividerUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; @@ -238,13 +221,6 @@ class ActivityStack extends Task { /** Stack is completely invisible. */ static final int STACK_VISIBILITY_INVISIBLE = 2; - /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to - * restrict IME adjustment so that a min portion of top stack remains visible.*/ - private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f; - - /** Dimming amount for non-focused stack when stacks are IME-adjusted. */ - private static final float IME_ADJUST_DIM_AMOUNT = 0.25f; - enum ActivityState { INITIALIZING, STARTED, @@ -294,28 +270,10 @@ class ActivityStack extends Task { /** For Pinned stack controlling. */ private Rect mTmpToBounds = new Rect(); - /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */ - private final Rect mAdjustedBounds = new Rect(); - - /** - * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they - * represent the state when the animation has ended. - */ - private final Rect mFullyAdjustedImeBounds = new Rect(); - /** Detach this stack from its display when animation completes. */ // TODO: maybe tie this to WindowContainer#removeChild some how... private boolean mDeferRemoval; - private final Rect mTmpAdjustedBounds = new Rect(); - private boolean mAdjustedForIme; - private boolean mImeGoingAway; - private WindowState mImeWin; - private float mMinimizeAmount; - private float mAdjustImeAmount; - private float mAdjustDividerAmount; - private final int mDockedStackMinimizeThickness; - // If this is true, we are in the bounds animating mode. The task will be down or upscaled to // perfectly fit the region it would have been cropped to. We may also avoid certain logic we // would otherwise apply while resizing, while resizing in the bounds animating mode. @@ -643,8 +601,6 @@ class ActivityStack extends Task { _realActivitySuspended, userSetupComplete, minWidth, minHeight, info, _voiceSession, _voiceInteractor, stack); - mDockedStackMinimizeThickness = mWmService.mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.docked_stack_minimize_thickness); EventLogTags.writeWmStackCreated(id); mHandler = new ActivityStackHandler(mStackSupervisor.mLooper); mCurrentUser = mAtmService.mAmInternal.getCurrentUserId(); @@ -1202,8 +1158,8 @@ class ActivityStack extends Task { @Override boolean isFocusable() { - return super.isFocusable() && !(inSplitScreenPrimaryWindowingMode() - && mRootWindowContainer.mIsDockMinimized); + // Special check for tile which isn't really in the hierarchy + return mTile != null ? mTile.isFocusable() : super.isFocusable(); } boolean isTopActivityFocusable() { @@ -3497,43 +3453,6 @@ class ActivityStack extends Task { forAllLeafTasks(Task::prepareFreezingBounds, true /* traverseTopToBottom */); } - /** - * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from - * the normal task bounds. - * - * @param bounds The adjusted bounds. - */ - private void setAdjustedBounds(Rect bounds) { - if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) { - return; - } - - mAdjustedBounds.set(bounds); - final boolean adjusted = !mAdjustedBounds.isEmpty(); - Rect insetBounds = null; - if (adjusted && isAdjustedForMinimizedDockedStack()) { - insetBounds = getRawBounds(); - } else if (adjusted && mAdjustedForIme) { - if (mImeGoingAway) { - insetBounds = getRawBounds(); - } else { - insetBounds = mFullyAdjustedImeBounds; - } - } - - if (!matchParentBounds()) { - final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP; - final PooledConsumer c = PooledLambda.obtainConsumer(Task::alignToAdjustedBounds, - PooledLambda.__(Task.class), adjusted ? mAdjustedBounds : getRawBounds(), - insetBounds, alignBottom); - forAllLeafTasks(c, true /* traverseTopToBottom */); - c.recycle(); - } - - mDisplayContent.setLayoutNeeded(); - updateSurfaceBounds(); - } - @Override public int setBounds(Rect bounds) { // Calling Task#setBounds() for leaf task since this is the a specialization of @@ -3552,8 +3471,6 @@ class ActivityStack extends Task { final int result = super.setBounds(!inMultiWindowMode() ? null : bounds); - updateAdjustedBounds(); - updateSurfaceBounds(); return result; } @@ -3575,19 +3492,6 @@ class ActivityStack extends Task { bounds.set(getBounds()); } - @Override - public Rect getBounds() { - // If we're currently adjusting for IME or minimized docked stack, we use the adjusted - // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked - // stack is visible since it is already what we want to represent to the rest of the - // system. - if (!mAdjustedBounds.isEmpty()) { - return mAdjustedBounds; - } else { - return super.getBounds(); - } - } - /** * @return the final bounds for the bounds animation. */ @@ -3620,113 +3524,6 @@ class ActivityStack extends Task { } /** - * Updates the passed-in {@code inOutBounds} based on the current state of the - * docked controller. This gets run *after* the override configuration is updated, so it's - * safe to rely on the controller's state in here (though eventually this dependence should - * be removed). - * - * This does NOT modify this TaskStack's configuration. However, it does, for the time-being, - * update docked controller state. - * - * @param parentConfig the parent configuration for reference. - * @param inOutBounds the bounds to update (both input and output). - */ - void calculateDockedBoundsForConfigChange(Configuration parentConfig, Rect inOutBounds) { - final boolean primary = - getRequestedOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; - repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds); - final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout; - snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds); - if (primary) { - final int newDockSide = getDockSide(parentConfig, inOutBounds); - // Update the dock create mode and clear the dock create bounds, these - // might change after a rotation and the original values will be invalid. - mWmService.setDockedStackCreateStateLocked( - (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP) - ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT - : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, - null); - mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide); - } - } - - /** - * Some primary split screen sides are not allowed by the policy. This method queries the policy - * and moves the primary stack around if needed. - * - * @param parentConfig the configuration of the stack's parent. - * @param primary true if adjusting the primary docked stack, false for secondary. - * @param inOutBounds the bounds of the stack to adjust. - */ - void repositionSplitScreenStackAfterRotation(Configuration parentConfig, boolean primary, - Rect inOutBounds) { - final int dockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds); - final int otherDockSide = DockedDividerUtils.invertDockSide(dockSide); - final int primaryDockSide = primary ? dockSide : otherDockSide; - if (mDisplayContent.getDockedDividerController() - .canPrimaryStackDockTo(primaryDockSide, - parentConfig.windowConfiguration.getBounds(), - parentConfig.windowConfiguration.getRotation())) { - return; - } - final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); - switch (otherDockSide) { - case DOCKED_LEFT: - int movement = inOutBounds.left; - inOutBounds.left -= movement; - inOutBounds.right -= movement; - break; - case DOCKED_RIGHT: - movement = parentBounds.right - inOutBounds.right; - inOutBounds.left += movement; - inOutBounds.right += movement; - break; - case DOCKED_TOP: - movement = inOutBounds.top; - inOutBounds.top -= movement; - inOutBounds.bottom -= movement; - break; - case DOCKED_BOTTOM: - movement = parentBounds.bottom - inOutBounds.bottom; - inOutBounds.top += movement; - inOutBounds.bottom += movement; - break; - } - } - - /** - * Snaps the bounds after rotation to the closest snap target for the docked stack. - */ - void snapDockedStackAfterRotation(Configuration parentConfig, DisplayCutout displayCutout, - Rect outBounds) { - - // Calculate the current position. - final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth(); - final int dockSide = getDockSide(parentConfig, outBounds); - final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds, - dockSide, dividerSize); - final int displayWidth = parentConfig.windowConfiguration.getBounds().width(); - final int displayHeight = parentConfig.windowConfiguration.getBounds().height(); - - // Snap the position to a target. - final int rotation = parentConfig.windowConfiguration.getRotation(); - final int orientation = parentConfig.orientation; - mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, displayWidth, displayHeight, - displayCutout, outBounds); - final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm( - mWmService.mContext.getResources(), displayWidth, displayHeight, - dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds, - getDockSide(), isMinimizedDockAndHomeStackResizable()); - final DividerSnapAlgorithm.SnapTarget target = - algorithm.calculateNonDismissingSnapTarget(dividerPosition); - - // Recalculate the bounds based on the position of the target. - DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide, - outBounds, displayWidth, displayHeight, - dividerSize); - } - - /** * Put a Task in this stack. Used for adding only. * When task is added to top of the stack, the entire branch of the hierarchy (including stack * and display) will be brought to top. @@ -3916,445 +3713,8 @@ class ActivityStack extends Task { } } - /** - * Determines the stack and task bounds of the other stack when in docked mode. The current task - * bounds is passed in but depending on the stack, the task and stack must match. Only in - * minimized mode with resizable launcher, the other stack ignores calculating the stack bounds - * and uses the task bounds passed in as the stack and task bounds, otherwise the stack bounds - * is calculated and is also used for its task bounds. - * If any of the out bounds are empty, it represents default bounds - * - * @param currentTempTaskBounds the current task bounds of the other stack - * @param outStackBounds the calculated stack bounds of the other stack - * @param outTempTaskBounds the calculated task bounds of the other stack - */ - void getStackDockedModeBounds(Rect dockedBounds, - Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds) { - final Configuration parentConfig = getParent().getConfiguration(); - outTempTaskBounds.setEmpty(); - - if (dockedBounds == null || dockedBounds.isEmpty()) { - // Calculate the primary docked bounds. - final boolean dockedOnTopOrLeft = mWmService.mDockedStackCreateMode - == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; - getStackDockedModeBounds(parentConfig, - true /* primary */, outStackBounds, dockedBounds, - mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); - return; - } - final int dockedSide = getDockSide(parentConfig, dockedBounds); - - // When the home stack is resizable, should always have the same stack and task bounds - if (isActivityTypeHome()) { - final Task homeTask = getTopMostTask(); - if (homeTask == null || homeTask.isResizeable()) { - // Calculate the home stack bounds when in docked mode and the home stack is - // resizeable. - getDisplayContent().mDividerControllerLocked - .getHomeStackBoundsInDockedMode(parentConfig, - dockedSide, outStackBounds); - } else { - // Home stack isn't resizeable, so don't specify stack bounds. - outStackBounds.setEmpty(); - } - - outTempTaskBounds.set(outStackBounds); - return; - } - - // When minimized state, the stack bounds for all non-home and docked stack bounds should - // match the passed task bounds - if (isMinimizedDockAndHomeStackResizable() && currentTempTaskBounds != null) { - outStackBounds.set(currentTempTaskBounds); - return; - } - - if (dockedSide == DOCKED_INVALID) { - // Not sure how you got here...Only thing we can do is return current bounds. - Slog.e(TAG_WM, "Failed to get valid docked side for docked stack"); - outStackBounds.set(getRawBounds()); - return; - } - - final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT; - getStackDockedModeBounds(parentConfig, - false /* primary */, outStackBounds, dockedBounds, - mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft); - } - - /** - * Outputs the bounds a stack should be given the presence of a docked stack on the display. - * @param parentConfig The parent configuration. - * @param primary {@code true} if getting the primary stack bounds. - * @param outBounds Output bounds that should be used for the stack. - * @param dockedBounds Bounds of the docked stack. - * @param dockDividerWidth We need to know the width of the divider make to the output bounds - * close to the side of the dock. - * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen. - */ - private void getStackDockedModeBounds(Configuration parentConfig, boolean primary, - Rect outBounds, Rect dockedBounds, int dockDividerWidth, - boolean dockOnTopOrLeft) { - final Rect displayRect = parentConfig.windowConfiguration.getBounds(); - final boolean splitHorizontally = displayRect.width() > displayRect.height(); - - outBounds.set(displayRect); - if (primary) { - if (mWmService.mDockedStackCreateBounds != null) { - outBounds.set(mWmService.mDockedStackCreateBounds); - return; - } - - // The initial bounds of the docked stack when it is created about half the screen space - // and its bounds can be adjusted after that. The bounds of all other stacks are - // adjusted to occupy whatever screen space the docked stack isn't occupying. - final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout; - mDisplayContent.getDisplayPolicy().getStableInsetsLw( - parentConfig.windowConfiguration.getRotation(), - displayRect.width(), displayRect.height(), displayCutout, mTmpRect2); - final int position = new DividerSnapAlgorithm(mWmService.mContext.getResources(), - displayRect.width(), - displayRect.height(), - dockDividerWidth, - parentConfig.orientation == ORIENTATION_PORTRAIT, - mTmpRect2).getMiddleTarget().position; - - if (dockOnTopOrLeft) { - if (splitHorizontally) { - outBounds.right = position; - } else { - outBounds.bottom = position; - } - } else { - if (splitHorizontally) { - outBounds.left = position + dockDividerWidth; - } else { - outBounds.top = position + dockDividerWidth; - } - } - return; - } - - // Other stacks occupy whatever space is left by the docked stack. - if (!dockOnTopOrLeft) { - if (splitHorizontally) { - outBounds.right = dockedBounds.left - dockDividerWidth; - } else { - outBounds.bottom = dockedBounds.top - dockDividerWidth; - } - } else { - if (splitHorizontally) { - outBounds.left = dockedBounds.right + dockDividerWidth; - } else { - outBounds.top = dockedBounds.bottom + dockDividerWidth; - } - } - DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft); - } - - void resetDockedStackToMiddle() { - if (!inSplitScreenPrimaryWindowingMode()) { - throw new IllegalStateException("Not a docked stack=" + this); - } - - mWmService.mDockedStackCreateBounds = null; - - final Rect bounds = new Rect(); - final Rect tempBounds = new Rect(); - getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */, - bounds, tempBounds); - mStackSupervisor.resizeDockedStackLocked(bounds, null /* tempTaskBounds */, - null /* tempTaskInsetBounds */, null /* tempOtherTaskBounds */, - null /* tempOtherTaskInsetBounds */, false /* preserveWindows */, - false /* deferResume */); - } - - /** - * Adjusts the stack bounds if the IME is visible. - * - * @param imeWin The IME window. - * @param keepLastAmount Use {@code true} to keep the last adjusted amount from - * {@link DockedStackDividerController} for adjusting the stack bounds, - * Use {@code false} to reset adjusted amount as 0. - * @see #updateAdjustForIme(float, float, boolean) - */ - void setAdjustedForIme(WindowState imeWin, boolean keepLastAmount) { - mImeWin = imeWin; - mImeGoingAway = false; - if (!mAdjustedForIme || keepLastAmount) { - mAdjustedForIme = true; - DockedStackDividerController controller = getDisplayContent().mDividerControllerLocked; - final float adjustImeAmount = keepLastAmount ? controller.mLastAnimationProgress : 0f; - final float adjustDividerAmount = keepLastAmount ? controller.mLastDividerProgress : 0f; - updateAdjustForIme(adjustImeAmount, adjustDividerAmount, true /* force */); - } - } - - boolean isAdjustedForIme() { - return mAdjustedForIme; - } - - boolean isAnimatingForIme() { - return mImeWin != null && mImeWin.isAnimatingLw(); - } - - /** - * Update the stack's bounds (crop or position) according to the IME window's - * current position. When IME window is animated, the bottom stack is animated - * together to track the IME window's current position, and the top stack is - * cropped as necessary. - * - * @return true if a traversal should be performed after the adjustment. - */ - boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) { - if (adjustAmount != mAdjustImeAmount - || adjustDividerAmount != mAdjustDividerAmount || force) { - mAdjustImeAmount = adjustAmount; - mAdjustDividerAmount = adjustDividerAmount; - updateAdjustedBounds(); - return isVisible(); - } else { - return false; - } - } - - /** - * Resets the adjustment after it got adjusted for the IME. - * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about - * animations; otherwise, set flag and animates the window away together - * with IME window. - */ - void resetAdjustedForIme(boolean adjustBoundsNow) { - if (adjustBoundsNow) { - mImeWin = null; - mImeGoingAway = false; - mAdjustImeAmount = 0f; - mAdjustDividerAmount = 0f; - if (!mAdjustedForIme) { - return; - } - mAdjustedForIme = false; - updateAdjustedBounds(); - mWmService.setResizeDimLayer(false, getWindowingMode(), 1.0f); - } else { - mImeGoingAway |= mAdjustedForIme; - } - } - - /** - * Sets the amount how much we currently minimize our stack. - * - * @param minimizeAmount The amount, between 0 and 1. - * @return Whether the amount has changed and a layout is needed. - */ - boolean setAdjustedForMinimizedDock(float minimizeAmount) { - if (minimizeAmount != mMinimizeAmount) { - mMinimizeAmount = minimizeAmount; - updateAdjustedBounds(); - return isVisible(); - } else { - return false; - } - } - boolean shouldIgnoreInput() { - return isAdjustedForMinimizedDockedStack() - || (inSplitScreenPrimaryWindowingMode() && isMinimizedDockAndHomeStackResizable()); - } - - /** - * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows - * to the list of to be drawn windows the service is waiting for. - */ - void beginImeAdjustAnimation() { - forAllLeafTasks((t) -> { - if (t.hasContentToDisplay()) { - t.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER); - t.setWaitingForDrawnIfResizingChanged(); - } - }, true /* traverseTopToBottom */); - } - - /** Resets the resizing state of all windows. */ - void endImeAdjustAnimation() { - forAllLeafTasks((t) -> { - t.setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER); - }, true /* traverseTopToBottom */); - } - - private int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) { - return displayContentRect.top + (int) - ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN); - } - - private boolean adjustForIME(final WindowState imeWin) { - // To prevent task stack resize animation may flicking when playing app transition - // animation & IME window enter animation in parallel, we need to make sure app - // transition is done and then adjust task size for IME, skip the new adjusted frame when - // app transition is still running. - if (getDisplayContent().mAppTransition.isRunning()) { - return false; - } - - final int dockedSide = getDockSide(); - final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM; - if (imeWin == null || !dockedTopOrBottom) { - return false; - } - - final Rect displayStableRect = mTmpRect; - final Rect contentBounds = mTmpRect2; - - // Calculate the content bounds excluding the area occupied by IME - getDisplayContent().getStableRect(displayStableRect); - contentBounds.set(displayStableRect); - int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top); - - imeTop += imeWin.getGivenContentInsetsLw().top; - if (contentBounds.bottom > imeTop) { - contentBounds.bottom = imeTop; - } - - final int yOffset = displayStableRect.bottom - contentBounds.bottom; - - final int dividerWidth = - getDisplayContent().mDividerControllerLocked.getContentWidth(); - final int dividerWidthInactive = - getDisplayContent().mDividerControllerLocked.getContentWidthInactive(); - - if (dockedSide == DOCKED_TOP) { - // If this stack is docked on top, we make it smaller so the bottom stack is not - // occluded by IME. We shift its bottom up by the height of the IME, but - // leaves at least 30% of the top stack visible. - final int minTopStackBottom = - getMinTopStackBottom(displayStableRect, getRawBounds().bottom); - final int bottom = Math.max( - getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive, - minTopStackBottom); - mTmpAdjustedBounds.set(getRawBounds()); - mTmpAdjustedBounds.bottom = (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) - * getRawBounds().bottom); - mFullyAdjustedImeBounds.set(getRawBounds()); - } else { - // When the stack is on bottom and has no focus, it's only adjusted for divider width. - final int dividerWidthDelta = dividerWidthInactive - dividerWidth; - - // When the stack is on bottom and has focus, it needs to be moved up so as to - // not occluded by IME, and at the same time adjusted for divider width. - // We try to move it up by the height of the IME window, but only to the extent - // that leaves at least 30% of the top stack visible. - // 'top' is where the top of bottom stack will move to in this case. - final int topBeforeImeAdjust = - getRawBounds().top - dividerWidth + dividerWidthInactive; - final int minTopStackBottom = - getMinTopStackBottom(displayStableRect, - getRawBounds().top - dividerWidth); - final int top = Math.max( - getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive); - - mTmpAdjustedBounds.set(getRawBounds()); - // Account for the adjustment for IME and divider width separately. - // (top - topBeforeImeAdjust) is the amount of movement due to IME only, - // and dividerWidthDelta is due to divider width change only. - mTmpAdjustedBounds.top = - getRawBounds().top + (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) - + mAdjustDividerAmount * dividerWidthDelta); - mFullyAdjustedImeBounds.set(getRawBounds()); - mFullyAdjustedImeBounds.top = top; - mFullyAdjustedImeBounds.bottom = top + getRawBounds().height(); - } - return true; - } - - private boolean adjustForMinimizedDockedStack(float minimizeAmount) { - final int dockSide = getDockSide(); - if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) { - return false; - } - - if (dockSide == DOCKED_TOP) { - mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect); - int topInset = mTmpRect.top; - mTmpAdjustedBounds.set(getRawBounds()); - mTmpAdjustedBounds.bottom = (int) (minimizeAmount * topInset + (1 - minimizeAmount) - * getRawBounds().bottom); - } else if (dockSide == DOCKED_LEFT) { - mTmpAdjustedBounds.set(getRawBounds()); - final int width = getRawBounds().width(); - mTmpAdjustedBounds.right = - (int) (minimizeAmount * mDockedStackMinimizeThickness - + (1 - minimizeAmount) * getRawBounds().right); - mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width; - } else if (dockSide == DOCKED_RIGHT) { - mTmpAdjustedBounds.set(getRawBounds()); - mTmpAdjustedBounds.left = - (int) (minimizeAmount * (getRawBounds().right - mDockedStackMinimizeThickness) - + (1 - minimizeAmount) * getRawBounds().left); - } - return true; - } - - boolean isMinimizedDockAndHomeStackResizable() { - return mDisplayContent.mDividerControllerLocked.isMinimizedDock() - && mDisplayContent.mDividerControllerLocked.isHomeStackResizable(); - } - - /** - * @return the distance in pixels how much the stack gets minimized from it's original size - */ - int getMinimizeDistance() { - final int dockSide = getDockSide(); - if (dockSide == DOCKED_INVALID) { - return 0; - } - - if (dockSide == DOCKED_TOP) { - mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect); - int topInset = mTmpRect.top; - return getRawBounds().bottom - topInset; - } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) { - return getRawBounds().width() - mDockedStackMinimizeThickness; - } else { - return 0; - } - } - - /** - * Updates the adjustment depending on it's current state. - */ - private void updateAdjustedBounds() { - boolean adjust = false; - if (mMinimizeAmount != 0f) { - adjust = adjustForMinimizedDockedStack(mMinimizeAmount); - } else if (mAdjustedForIme) { - adjust = adjustForIME(mImeWin); - } - if (!adjust) { - mTmpAdjustedBounds.setEmpty(); - } - setAdjustedBounds(mTmpAdjustedBounds); - - final boolean isImeTarget = (mWmService.getImeFocusStackLocked() == this); - if (mAdjustedForIme && adjust && !isImeTarget) { - final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount) - * IME_ADJUST_DIM_AMOUNT; - mWmService.setResizeDimLayer(true, getWindowingMode(), alpha); - } - } - - void applyAdjustForImeIfNeeded(Task task) { - if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) { - return; - } - - final Rect insetBounds = mImeGoingAway ? getRawBounds() : mFullyAdjustedImeBounds; - task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP); - mDisplayContent.setLayoutNeeded(); - } - - - boolean isAdjustedForMinimizedDockedStack() { - return mMinimizeAmount != 0f; + return inSplitScreenPrimaryWindowingMode() && !isFocusable(); } @Override @@ -4362,17 +3722,6 @@ class ActivityStack extends Task { pw.println(prefix + "mStackId=" + getRootTaskId()); pw.println(prefix + "mDeferRemoval=" + mDeferRemoval); pw.println(prefix + "mBounds=" + getRawBounds().toShortString()); - if (mMinimizeAmount != 0f) { - pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount); - } - if (mAdjustedForIme) { - pw.println(prefix + "mAdjustedForIme=true"); - pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount); - pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount); - } - if (!mAdjustedBounds.isEmpty()) { - pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString()); - } for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) { mChildren.get(taskNdx).dump(pw, prefix + " ", dumpAll); } @@ -4391,39 +3740,6 @@ class ActivityStack extends Task { } /** - * For docked workspace (or workspace that's side-by-side to the docked), provides - * information which side of the screen was the dock anchored. - */ - int getDockSide() { - return getDockSide(mDisplayContent.getConfiguration(), getRawBounds()); - } - - int getDockSideForDisplay(DisplayContent dc) { - return getDockSide(dc, dc.getConfiguration(), getRawBounds()); - } - - int getDockSide(Configuration parentConfig, Rect bounds) { - if (mDisplayContent == null) { - return DOCKED_INVALID; - } - return getDockSide(mDisplayContent, parentConfig, bounds); - } - - private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) { - return dc.getDockedDividerController().getDockSide(bounds, - parentConfig.windowConfiguration.getBounds(), - parentConfig.orientation, parentConfig.windowConfiguration.getRotation()); - } - - boolean hasTaskForUser(int userId) { - final PooledPredicate p = PooledLambda.obtainPredicate( - Task::isTaskForUser, PooledLambda.__(Task.class), userId); - final Task task = getTask(p); - p.recycle(); - return task != null; - } - - /** * Sets the current picture-in-picture aspect ratio. */ void setPictureInPictureAspectRatio(float aspectRatio) { @@ -4639,16 +3955,11 @@ class ActivityStack extends Task { bounds.dumpDebug(proto, BOUNDS); } getOverrideDisplayedBounds().dumpDebug(proto, DISPLAYED_BOUNDS); - mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS); if (mLastNonFullscreenBounds != null) { mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS); } proto.write(DEFER_REMOVAL, mDeferRemoval); - proto.write(MINIMIZE_AMOUNT, mMinimizeAmount); - proto.write(ADJUSTED_FOR_IME, mAdjustedForIme); - proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount); - proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount); proto.write(ANIMATING_BOUNDS, mBoundsAnimating); if (mSurfaceControl != null) { diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index b2d2f624e458..6d7f8fb6adde 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -35,12 +35,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.graphics.Rect.copyOrNull; import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; @@ -210,17 +208,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { /** True if the docked stack is currently being resized. */ private boolean mDockedStackResizing; - /** - * True if there are pending docked bounds that need to be applied after - * {@link #mDockedStackResizing} is reset to false. - */ - private boolean mHasPendingDockedBounds; - private Rect mPendingDockedBounds; - private Rect mPendingTempDockedTaskBounds; - private Rect mPendingTempDockedTaskInsetBounds; - private Rect mPendingTempOtherTaskBounds; - private Rect mPendingTempOtherTaskInsetBounds; - // Activity actions an app cannot start if it uses a permission which is not granted. private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION = new ArrayMap<>(); @@ -387,15 +374,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { */ private final ArraySet<Integer> mResizingTasksDuringAnimation = new ArraySet<>(); - - /** - * If set to {@code false} all calls to resize the docked stack {@link #resizeDockedStackLocked} - * will be ignored. Useful for the case where the caller is handling resizing of other stack and - * moving tasks around and doesn't want dock stack to be resized due to an automatic trigger - * like the docked stack going empty. - */ - private boolean mAllowDockedStackResize = true; - private KeyguardController mKeyguardController; private PowerManager mPowerManager; @@ -1541,12 +1519,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED); } - - // Also disable docked stack resizing since we have manually adjusted the - // size of other stacks above and we don't want to trigger a docked stack - // resize when we remove task from it below and it is detached from the - // display because it no longer contains any tasks. - mAllowDockedStackResize = false; } // If we are moving from the pinned stack, then the animation takes care of updating @@ -1563,7 +1535,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); mRootWindowContainer.resumeFocusedStacksTopActivities(); } finally { - mAllowDockedStackResize = true; mService.continueWindowLayout(); } } @@ -1580,120 +1551,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mDockedStackResizing = resizing; mWindowManager.setDockedStackResizing(resizing); - - if (!resizing && mHasPendingDockedBounds) { - resizeDockedStackLocked(mPendingDockedBounds, mPendingTempDockedTaskBounds, - mPendingTempDockedTaskInsetBounds, mPendingTempOtherTaskBounds, - mPendingTempOtherTaskInsetBounds, PRESERVE_WINDOWS); - - mHasPendingDockedBounds = false; - mPendingDockedBounds = null; - mPendingTempDockedTaskBounds = null; - mPendingTempDockedTaskInsetBounds = null; - mPendingTempOtherTaskBounds = null; - mPendingTempOtherTaskInsetBounds = null; - } - } - - void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, - Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, - boolean preserveWindows) { - resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds, tempDockedTaskInsetBounds, - tempOtherTaskBounds, tempOtherTaskInsetBounds, preserveWindows, - false /* deferResume */); - } - - void resizeDockedStackLocked(Rect displayedBounds, Rect tempDockedTaskBounds, - Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, - boolean preserveWindows, boolean deferResume) { - - if (!mAllowDockedStackResize) { - // Docked stack resize currently disabled. - return; - } - - final ActivityStack stack = - mRootWindowContainer.getDefaultDisplay().getRootSplitScreenPrimaryTask(); - if (stack == null) { - Slog.w(TAG, "resizeDockedStackLocked: docked stack not found"); - return; - } - - if (mDockedStackResizing) { - mHasPendingDockedBounds = true; - mPendingDockedBounds = copyOrNull(displayedBounds); - mPendingTempDockedTaskBounds = copyOrNull(tempDockedTaskBounds); - mPendingTempDockedTaskInsetBounds = copyOrNull(tempDockedTaskInsetBounds); - mPendingTempOtherTaskBounds = copyOrNull(tempOtherTaskBounds); - mPendingTempOtherTaskInsetBounds = copyOrNull(tempOtherTaskInsetBounds); - } - - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeDockedStack"); - mService.deferWindowLayout(); - try { - // Don't allow re-entry while resizing. E.g. due to docked stack detaching. - mAllowDockedStackResize = false; - ActivityRecord r = stack.topRunningActivity(); - stack.resize(displayedBounds, tempDockedTaskBounds, - !PRESERVE_WINDOWS, DEFER_RESUME); - - // TODO: Checking for isAttached might not be needed as if the user passes in null - // dockedBounds then they want the docked stack to be dismissed. - if (stack.getWindowingMode() == WINDOWING_MODE_FULLSCREEN - || (displayedBounds == null && !stack.isAttached())) { - // The dock stack either was dismissed or went fullscreen, which is kinda the same. - // In this case we make all other static stacks fullscreen and move all - // docked stack tasks to the fullscreen stack. - moveTasksToFullscreenStackLocked(stack, ON_TOP); - - // stack shouldn't contain anymore activities, so nothing to resume. - r = null; - } else { - // Docked stacks occupy a dedicated region on screen so the size of all other - // static stacks need to be adjusted so they don't overlap with the docked stack. - // We get the bounds to use from window manager which has been adjusted for any - // screen controls and is also the same for all stacks. - final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); - final Rect otherTaskRect = new Rect(); - for (int i = display.getStackCount() - 1; i >= 0; --i) { - final ActivityStack current = display.getStackAt(i); - if (!current.inSplitScreenSecondaryWindowingMode()) { - continue; - } - if (!current.affectedBySplitScreenResize()) { - continue; - } - if (mDockedStackResizing && !current.isTopActivityVisible()) { - // Non-visible stacks get resized once we're done with the resize - // interaction. - continue; - } - current.getStackDockedModeBounds(displayedBounds, - tempOtherTaskBounds /* currentTempTaskBounds */, - tempRect /* outStackBounds */, - otherTaskRect /* outTempTaskBounds */); - - if (tempRect.isEmpty()) { - // If this scenario is hit, it means something is not working right. - // Empty/null bounds implies fullscreen. In the event that this stack - // *should* be fullscreen, its mode should be set explicitly in a form - // of setWindowingMode so that other parts of the system are updated - // properly. - throw new IllegalArgumentException("Trying to set null bounds on a" - + " non-fullscreen stack"); - } - - current.resize(tempRect, tempOtherTaskBounds, preserveWindows, deferResume); - } - } - if (!deferResume) { - stack.ensureVisibleActivitiesConfiguration(r, preserveWindows); - } - } finally { - mAllowDockedStackResize = true; - mService.continueWindowLayout(); - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - } } private void removeStackInSurfaceTransaction(ActivityStack stack) { @@ -2723,9 +2580,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mService.deferWindowLayout(); try { if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - mWindowManager.setDockedStackCreateStateLocked( - activityOptions.getSplitScreenCreateMode(), null /* initialBounds */); - // Defer updating the stack in which recents is until the app transition is done, to // not run into issues where we still need to draw the task in recents but the // docked stack is already created. @@ -2801,24 +2655,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // the window renders full-screen with the background filling the void. Also only // call this at the end to make sure that tasks exists on the window manager side. setResizingDuringAnimation(task); - - final DisplayContent display = task.getStack().getDisplay(); - final ActivityStack topSecondaryStack = - display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - if (topSecondaryStack != null && topSecondaryStack.isActivityTypeHome()) { - // If the home activity is the top split-screen secondary stack, then the - // primary split-screen stack is in the minimized mode which means it can't - // receive input keys, so we should move the focused app to the home app so that - // window manager can correctly calculate the focus window that can receive - // input keys. - display.moveHomeActivityToTop( - "startActivityFromRecents: homeVisibleInSplitScreen"); - - // Immediately update the minimized docked stack mode, the upcoming animation - // for the docked activity (WMS.overridePendingAppTransitionMultiThumbFuture) - // will do the animation to the target bounds - mWindowManager.checkSplitScreenMinimizedChanged(false /* animate */); - } } mService.continueWindowLayout(); } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index f52c7f29ac8a..32103048469f 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1819,12 +1819,12 @@ class ActivityStarter { */ private int deliverToCurrentTopIfNeeded(ActivityStack topStack) { final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop); - final boolean dontStart = top != null + final boolean dontStart = top != null && mStartActivity.resultTo == null && top.mActivityComponent.equals(mStartActivity.mActivityComponent) && top.mUserId == mStartActivity.mUserId && top.attachedToProcess() && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 - || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)) + || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)) // This allows home activity to automatically launch on secondary display when // display added, if home was the top activity on default display, instead of // sending new intent to the home activity on default display. @@ -2055,6 +2055,8 @@ class ActivityStarter { && !isLaunchModeOneOf(LAUNCH_SINGLE_TASK, LAUNCH_SINGLE_INSTANCE) && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0; + sendNewTaskResultRequestIfNeeded(); + if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) { mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } @@ -2236,8 +2238,6 @@ class ActivityStarter { mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK; } } - - sendNewTaskResultRequestIfNeeded(); } private void computeSourceStack() { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 510072d3831b..ca856ca7c1e6 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -169,12 +169,6 @@ public abstract class ActivityTaskManagerInternal { public abstract List<IBinder> getTopVisibleActivities(); /** - * Callback for window manager to let activity manager know that docked stack changes its - * minimized state. - */ - public abstract void notifyDockedStackMinimizedChanged(boolean minimized); - - /** * Notify listeners that contents are drawn for the first time on a single task display. * * @param displayId An ID of the display on which contents are drawn. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 693a5e499552..770dabf4f5ca 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -31,12 +31,12 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW; -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -2309,9 +2309,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) { if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - return setTaskWindowingModeSplitScreenPrimary(taskId, - SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, - toTop, ANIMATE, null /* initialBounds */, true /* showRecents */); + return setTaskWindowingModeSplitScreenPrimary(taskId, toTop); } enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()"); synchronized (mGlobalLock) { @@ -2681,10 +2679,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { throw new IllegalArgumentException("moveTaskToStack: Attempt to move task " + taskId + " to stack " + stackId); } - if (stack.inSplitScreenPrimaryWindowingMode()) { - mWindowManager.setDockedStackCreateStateLocked( - SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, null /* initialBounds */); - } task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, "moveTaskToStack"); } finally { @@ -2697,22 +2691,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * Moves the specified task to the primary-split-screen stack. * * @param taskId Id of task to move. - * @param createMode The mode the primary split screen stack should be created in if it doesn't - * exist already. See - * {@link android.app.ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT} - * and - * {@link android.app.ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT} * @param toTop If the task and stack should be moved to the top. - * @param animate Whether we should play an animation for the moving the task. - * @param initialBounds If the primary stack gets created, it will use these bounds for the - * stack. Pass {@code null} to use default bounds. - * @param showRecents If the recents activity should be shown on the other side of the task - * going into split-screen mode. * @return Whether the task was successfully put into splitscreen. */ @Override - public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, - boolean toTop, boolean animate, Rect initialBounds, boolean showRecents) { + public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop) { enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingModeSplitScreenPrimary()"); synchronized (mGlobalLock) { @@ -4273,6 +4256,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + // TODO(b/149338177): remove when CTS no-longer requires it @Override public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds, Rect tempDockedTaskInsetBounds, @@ -4281,9 +4265,42 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - mStackSupervisor.resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds, - tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds, - PRESERVE_WINDOWS); + final DisplayContent dc = mRootWindowContainer.getDefaultDisplay(); + TaskTile primary = null; + TaskTile secondary = null; + for (int i = dc.getStackCount() - 1; i >= 0; --i) { + final TaskTile t = dc.getStackAt(i).asTile(); + if (t == null) { + continue; + } + if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + primary = t; + } else if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) { + secondary = t; + } + } + if (primary == null || secondary == null) { + return; + } + final WindowContainerTransaction wct = new WindowContainerTransaction(); + final Rect primaryRect = + tempDockedTaskInsetBounds != null ? tempDockedTaskInsetBounds + : (tempDockedTaskBounds != null ? tempDockedTaskBounds + : dockedBounds); + wct.setBounds(primary.mRemoteToken, primaryRect); + Rect otherRect = tempOtherTaskInsetBounds != null ? tempOtherTaskInsetBounds + : tempOtherTaskBounds; + if (otherRect == null) { + // Temporary estimation... again this is just for tests. + otherRect = new Rect(secondary.getBounds()); + if (dc.getBounds().width() > dc.getBounds().height()) { + otherRect.left = primaryRect.right + 6; + } else { + otherRect.top = primaryRect.bottom + 6; + } + } + wct.setBounds(secondary.mRemoteToken, otherRect); + mTaskOrganizerController.applyContainerTransaction(wct, null /* organizer */); } } finally { Binder.restoreCallingIdentity(ident); @@ -5868,8 +5885,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * Return the intent set with {@link Intent#CATEGORY_SECONDARY_HOME} to resolve secondary home * activities. * - * @param preferredPackage Specify a preferred package name, otherwise use secondary home - * component defined in config_secondaryHomeComponent. + * @param preferredPackage Specify a preferred package name, otherwise use the package name + * defined in config_secondaryHomePackage. * @return the intent set with {@link Intent#CATEGORY_SECONDARY_HOME} */ Intent getSecondaryHomeIntent(String preferredPackage) { @@ -5877,10 +5894,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final boolean useSystemProvidedLauncher = mContext.getResources().getBoolean( com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary); if (preferredPackage == null || useSystemProvidedLauncher) { - // Using the component stored in config if no package name or forced. - final String secondaryHomeComponent = mContext.getResources().getString( - com.android.internal.R.string.config_secondaryHomeComponent); - intent.setComponent(ComponentName.unflattenFromString(secondaryHomeComponent)); + // Using the package name stored in config if no preferred package name or forced. + final String secondaryHomePackage = mContext.getResources().getString( + com.android.internal.R.string.config_secondaryHomePackage); + intent.setPackage(secondaryHomePackage); } else { intent.setPackage(preferredPackage); } @@ -6136,13 +6153,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public void notifyDockedStackMinimizedChanged(boolean minimized) { - synchronized (mGlobalLock) { - mRootWindowContainer.setDockedStackMinimized(minimized); - } - } - - @Override public int startActivitiesAsPackage(String packageName, @Nullable String featureId, int userId, Intent[] intents, Bundle bOptions) { Objects.requireNonNull(intents, "intents"); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 8cf08814096e..f86aeb2244dc 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -172,6 +172,7 @@ public class AppTransition implements Dump { private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420; private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336; private static final long APP_TRANSITION_TIMEOUT_MS = 5000; + static final int MAX_APP_TRANSITION_DURATION = 3 * 1000; // 3 secs. private final Context mContext; private final WindowManagerService mService; @@ -446,8 +447,6 @@ public class AppTransition implements Dump { ? topOpeningAnim.getStatusBarTransitionsStartTime() : SystemClock.uptimeMillis(), AnimationAdapter.STATUS_BAR_TRANSITION_DURATION); - mDisplayContent.getDockedDividerController() - .notifyAppTransitionStarting(openingApps, transit); if (mRemoteAnimationController != null) { mRemoteAnimationController.goodToGo(); @@ -2308,14 +2307,14 @@ public class AppTransition implements Dump { } notifyAppTransitionTimeoutLocked(); if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty() - || !dc.mChangingApps.isEmpty()) { + || !dc.mChangingContainers.isEmpty()) { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b " + "mOpeningApps.size()=%d mClosingApps.size()=%d " + "mChangingApps.size()=%d", dc.getDisplayId(), dc.mAppTransition.isTransitionSet(), dc.mOpeningApps.size(), dc.mClosingApps.size(), - dc.mChangingApps.size()); + dc.mChangingContainers.size()); setTimeout(); mService.mWindowPlacerLocked.performSurfacePlacement(); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 3f4e79162ed9..0912b2e8b52f 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -55,6 +55,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.NonNull; import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; @@ -86,7 +87,7 @@ public class AppTransitionController { private final WallpaperController mWallpaperControllerLocked; private RemoteAnimationDefinition mRemoteAnimationDefinition = null; - private final ArrayMap<ActivityRecord, Integer> mTempTransitionReasons = new ArrayMap<>(); + private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>(); AppTransitionController(WindowManagerService service, DisplayContent displayContent) { mService = service; @@ -104,7 +105,8 @@ public class AppTransitionController { void handleAppTransitionReady() { mTempTransitionReasons.clear(); if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons) - || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) { + || !transitionGoodToGo(mDisplayContent.mChangingContainers, + mTempTransitionReasons)) { return; } Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady"); @@ -130,17 +132,21 @@ public class AppTransitionController { // transition selection depends on wallpaper target visibility. mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags(); } - appCount = mDisplayContent.mChangingApps.size(); + appCount = mDisplayContent.mChangingContainers.size(); for (int i = 0; i < appCount; ++i) { // Clearing for same reason as above. - mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags(); + final ActivityRecord activity = getAppFromContainer( + mDisplayContent.mChangingContainers.valueAtUnchecked(i)); + if (activity != null) { + activity.clearAnimatingFlags(); + } } // Adjust wallpaper before we pull the lower/upper target, since pending changes // (like the clearAnimatingFlags() above) might affect wallpaper target result. // Or, the opening app window should be a wallpaper target. mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded( - mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps); + mDisplayContent.mOpeningApps); // Determine if closing and opening app token sets are wallpaper targets, in which case // special animations are needed. @@ -159,7 +165,7 @@ public class AppTransitionController { // no need to do an animation. This is the case, for example, when this transition is being // done behind a dream window. final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps, - mDisplayContent.mClosingApps, mDisplayContent.mChangingApps); + mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers); final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw(); final ActivityRecord animLpActivity = allowAnimations ? findAnimLayoutParamsToken(transit, activityTypes) @@ -171,14 +177,13 @@ public class AppTransitionController { ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */) : null; final ActivityRecord topChangingApp = allowAnimations - ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */) + ? getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */) : null; final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity); overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes); final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps) - || containsVoiceInteraction(mDisplayContent.mOpeningApps) - || containsVoiceInteraction(mDisplayContent.mChangingApps); + || containsVoiceInteraction(mDisplayContent.mOpeningApps); final int layoutRedo; mService.mSurfaceAnimationRunner.deferStartingAnimations(); @@ -206,7 +211,7 @@ public class AppTransitionController { mDisplayContent.mOpeningApps.clear(); mDisplayContent.mClosingApps.clear(); - mDisplayContent.mChangingApps.clear(); + mDisplayContent.mChangingContainers.clear(); mDisplayContent.mUnknownAppVisibilityController.clear(); // This has changed the visibility of windows, so perform @@ -235,9 +240,9 @@ public class AppTransitionController { return mainWindow != null ? mainWindow.mAttrs : null; } - RemoteAnimationAdapter getRemoteAnimationOverride(ActivityRecord animLpActivity, + RemoteAnimationAdapter getRemoteAnimationOverride(@NonNull WindowContainer container, @TransitionType int transit, ArraySet<Integer> activityTypes) { - final RemoteAnimationDefinition definition = animLpActivity.getRemoteAnimationDefinition(); + final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition(); if (definition != null) { final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes); if (adapter != null) { @@ -271,6 +276,11 @@ public class AppTransitionController { } } + static ActivityRecord getAppFromContainer(WindowContainer wc) { + return wc.asTask() != null ? wc.asTask().getTopNonFinishingActivity() + : wc.asActivityRecord(); + } + /** * @return The window token that determines the animation theme. */ @@ -279,14 +289,14 @@ public class AppTransitionController { ActivityRecord result; final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps; final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps; - final ArraySet<ActivityRecord> changingApps = mDisplayContent.mChangingApps; + final ArraySet<WindowContainer> changingApps = mDisplayContent.mChangingContainers; // Remote animations always win, but fullscreen tokens override non-fullscreen tokens. result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps, w -> w.getRemoteAnimationDefinition() != null && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes)); if (result != null) { - return result; + return getAppFromContainer(result); } result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps, w -> w.fillsParent() && w.findMainWindow() != null); @@ -302,7 +312,7 @@ public class AppTransitionController { * of apps in {@code array1}, {@code array2}, and {@code array3}. */ private static ArraySet<Integer> collectActivityTypes(ArraySet<ActivityRecord> array1, - ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3) { + ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3) { final ArraySet<Integer> result = new ArraySet<>(); for (int i = array1.size() - 1; i >= 0; i--) { result.add(array1.valueAt(i).getActivityType()); @@ -317,7 +327,7 @@ public class AppTransitionController { } private static ActivityRecord lookForHighestTokenWithFilter(ArraySet<ActivityRecord> array1, - ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3, + ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3, Predicate<ActivityRecord> filter) { final int array2base = array1.size(); final int array3base = array2.size() + array2base; @@ -325,15 +335,16 @@ public class AppTransitionController { int bestPrefixOrderIndex = Integer.MIN_VALUE; ActivityRecord bestToken = null; for (int i = 0; i < count; i++) { - final ActivityRecord wtoken = i < array2base + final WindowContainer wtoken = i < array2base ? array1.valueAt(i) : (i < array3base ? array2.valueAt(i - array2base) : array3.valueAt(i - array3base)); final int prefixOrderIndex = wtoken.getPrefixOrderIndex(); - if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) { + final ActivityRecord r = getAppFromContainer(wtoken); + if (r != null && filter.test(r) && prefixOrderIndex > bestPrefixOrderIndex) { bestPrefixOrderIndex = prefixOrderIndex; - bestToken = wtoken; + bestToken = r; } } return bestToken; @@ -589,21 +600,13 @@ public class AppTransitionController { } private void handleChangingApps(@TransitionType int transit) { - final ArraySet<ActivityRecord> apps = mDisplayContent.mChangingApps; + final ArraySet<WindowContainer> apps = mDisplayContent.mChangingContainers; final int appsCount = apps.size(); for (int i = 0; i < appsCount; i++) { - ActivityRecord activity = apps.valueAt(i); - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", activity); - activity.cancelAnimationOnly(); - activity.applyAnimation(null, transit, true, false, + WindowContainer wc = apps.valueAt(i); + ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wc); + wc.applyAnimation(null, transit, true, false, null /* animationFinishedCallback */); - activity.updateReportedVisibilityLocked(); - mService.openSurfaceTransaction(); - try { - activity.showAllWindowsLocked(); - } finally { - mService.closeSurfaceTransaction("handleChangingApps"); - } } } @@ -628,8 +631,8 @@ public class AppTransitionController { } } - private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps, - ArrayMap<ActivityRecord, Integer> outReasons) { + private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps, + ArrayMap<WindowContainer, Integer> outReasons) { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(), mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout()); @@ -652,13 +655,17 @@ public class AppTransitionController { return false; } for (int i = 0; i < apps.size(); i++) { - ActivityRecord activity = apps.valueAt(i); + WindowContainer wc = apps.valueAt(i); + final ActivityRecord activity = getAppFromContainer(wc); + if (activity == null) { + continue; + } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Check opening app=%s: allDrawn=%b startingDisplayed=%b " - + "startingMoved=%b isRelaunching()=%b startingWindow=%s", - activity, activity.allDrawn, activity.startingDisplayed, - activity.startingMoved, activity.isRelaunching(), - activity.startingWindow); + "Check opening app=%s: allDrawn=%b startingDisplayed=%b " + + "startingMoved=%b isRelaunching()=%b startingWindow=%s", + activity, activity.allDrawn, activity.startingDisplayed, + activity.startingMoved, activity.isRelaunching(), + activity.startingWindow); final boolean allDrawn = activity.allDrawn && !activity.isRelaunching(); @@ -838,7 +845,7 @@ public class AppTransitionController { @VisibleForTesting boolean isTransitWithinTask(@TransitionType int transit, Task task) { if (task == null - || !mDisplayContent.mChangingApps.isEmpty()) { + || !mDisplayContent.mChangingContainers.isEmpty()) { // if there is no task, then we can't constrain to the task. // if anything is changing, it can animate outside its task. return false; @@ -882,12 +889,13 @@ public class AppTransitionController { * {@link ActivityRecord#isVisible}. * @return The top {@link ActivityRecord}. */ - private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreInvisible) { + private ActivityRecord getTopApp(ArraySet<? extends WindowContainer> apps, + boolean ignoreInvisible) { int topPrefixOrderIndex = Integer.MIN_VALUE; ActivityRecord topApp = null; for (int i = apps.size() - 1; i >= 0; i--) { - final ActivityRecord app = apps.valueAt(i); - if (ignoreInvisible && !app.isVisible()) { + final ActivityRecord app = getAppFromContainer(apps.valueAt(i)); + if (app == null || ignoreInvisible && !app.isVisible()) { continue; } final int prefixOrderIndex = app.getPrefixOrderIndex(); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 8ccb59f39081..5cd29301c733 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -91,11 +91,9 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK; import static com.android.server.wm.DisplayContentProto.APP_TRANSITION; -import static com.android.server.wm.DisplayContentProto.CHANGING_APPS; import static com.android.server.wm.DisplayContentProto.CLOSING_APPS; import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES; import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO; -import static com.android.server.wm.DisplayContentProto.DOCKED_STACK_DIVIDER_CONTROLLER; import static com.android.server.wm.DisplayContentProto.DPI; import static com.android.server.wm.DisplayContentProto.FOCUSED_APP; import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID; @@ -132,7 +130,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE; import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE; import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS; -import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER; +import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_STACKS; import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT; import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD; import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION; @@ -314,7 +312,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final ArraySet<ActivityRecord> mOpeningApps = new ArraySet<>(); final ArraySet<ActivityRecord> mClosingApps = new ArraySet<>(); - final ArraySet<ActivityRecord> mChangingApps = new ArraySet<>(); + final ArraySet<WindowContainer> mChangingContainers = new ArraySet<>(); final UnknownAppVisibilityController mUnknownAppVisibilityController; private MetricsLogger mMetricsLogger; @@ -1006,7 +1004,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mDisplayPolicy.systemReady(); } mWindowCornerRadius = mDisplayPolicy.getWindowCornerRadius(); - mDividerControllerLocked = new DockedStackDividerController(mWmService, this); + mDividerControllerLocked = new DockedStackDividerController(this); mPinnedStackControllerLocked = new PinnedStackController(mWmService, this); final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(mSession) @@ -2233,12 +2231,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * for bounds calculations. */ void preOnConfigurationChanged() { - final DockedStackDividerController dividerController = getDockedDividerController(); - - if (dividerController != null) { - getDockedDividerController().onConfigurationChanged(); - } - final PinnedStackController pinnedStackController = getPinnedStackController(); if (pinnedStackController != null) { @@ -2622,10 +2614,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // We also remove the outside touch area for resizing for all freeform // tasks (including the focused). // We save the focused task region once we find it, and add it back at the end. - // If the task is home stack and it is resizable in the minimized state, we want to - // exclude the docked stack from touch so we need the entire screen area and not just a + // If the task is home stack and it is resizable and visible (top of its root task), we want + // to exclude the docked stack from touch so we need the entire screen area and not just a // small portion which the home stack currently is resized to. - if (task.isActivityTypeHome() && task.getStack().isMinimizedDockAndHomeStackResizable()) { + if (task.isActivityTypeHome() && task.isVisible() && task.getStack().getTile() != null + && task.isResizeable()) { mDisplayContent.getBounds(mTmpRect); } else { task.getDimBounds(mTmpRect); @@ -2634,6 +2627,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (task == focusedTask) { // Add the focused task rect back into the exclude region once we are done // processing stacks. + // NOTE: this *looks* like a no-op, but this usage of mTmpRect2 is expected by + // updateTouchExcludeRegion. mTmpRect2.set(mTmpRect); } @@ -2695,7 +2690,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // Clear all transitions & screen frozen states when removing display. mOpeningApps.clear(); mClosingApps.clear(); - mChangingApps.clear(); + mChangingContainers.clear(); mUnknownAppVisibilityController.clear(); mAppTransition.removeAppTransitionTimeoutCallbacks(); handleAnimatingStoppedAndTransition(); @@ -2712,6 +2707,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mRemovingDisplay = false; } + // Apply the pending transaction here since we may not be able to reach the DisplayContent + // on the next traversal if it's removed from RootWindowContainer child list. + getPendingTransaction().apply(); mWmService.mWindowPlacerLocked.requestTraversal(); } @@ -2744,58 +2742,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mDeferredRemoval; } - boolean animateForIme(float interpolatedValue, float animationTarget, - float dividerAnimationTarget) { - boolean updated = false; - - for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = mTaskContainers.getChildAt(i); - if (stack == null || !stack.isAdjustedForIme()) { - continue; - } - - if (interpolatedValue >= 1f && animationTarget == 0f && dividerAnimationTarget == 0f) { - stack.resetAdjustedForIme(true /* adjustBoundsNow */); - updated = true; - } else { - mDividerControllerLocked.mLastAnimationProgress = - mDividerControllerLocked.getInterpolatedAnimationValue(interpolatedValue); - mDividerControllerLocked.mLastDividerProgress = - mDividerControllerLocked.getInterpolatedDividerValue(interpolatedValue); - updated |= stack.updateAdjustForIme( - mDividerControllerLocked.mLastAnimationProgress, - mDividerControllerLocked.mLastDividerProgress, - false /* force */); - } - if (interpolatedValue >= 1f) { - stack.endImeAdjustAnimation(); - } - } - - return updated; - } - - boolean clearImeAdjustAnimation() { - boolean changed = false; - for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = mTaskContainers.getChildAt(i); - if (stack != null && stack.isAdjustedForIme()) { - stack.resetAdjustedForIme(true /* adjustBoundsNow */); - changed = true; - } - } - return changed; - } - - void beginImeAdjustAnimation() { - for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = mTaskContainers.getChildAt(i); - if (stack.isVisible() && stack.isAdjustedForIme()) { - stack.beginImeAdjustAnimation(); - } - } - } - void adjustForImeIfNeeded() { final WindowState imeWin = mInputMethodWindow; final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() @@ -2890,7 +2836,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final ActivityStack stack = mTaskContainers.getChildAt(i); stack.dumpDebug(proto, TASKS, logLevel); } - mDividerControllerLocked.dumpDebug(proto, DOCKED_STACK_DIVIDER_CONTROLLER); for (int i = mOverlayContainers.getChildCount() - 1; i >= 0; --i) { final WindowToken windowToken = mOverlayContainers.getChildAt(i); windowToken.dumpDebug(proto, OVERLAY_WINDOWS, logLevel); @@ -2913,9 +2858,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo for (int i = mClosingApps.size() - 1; i >= 0; i--) { mClosingApps.valueAt(i).writeIdentifierToProto(proto, CLOSING_APPS); } - for (int i = mChangingApps.size() - 1; i >= 0; i--) { - mChangingApps.valueAt(i).writeIdentifierToProto(proto, CHANGING_APPS); - } proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance); final ActivityStack focusedStack = getFocusedStack(); @@ -3063,8 +3005,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } pw.println(); - mDividerControllerLocked.dump(prefix, pw); - pw.println(); mPinnedStackControllerLocked.dump(prefix, pw); pw.println(); @@ -3667,7 +3607,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } - if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingApps.isEmpty()) { + if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingContainers.isEmpty()) { pw.println(); if (mOpeningApps.size() > 0) { pw.print(" mOpeningApps="); pw.println(mOpeningApps); @@ -3675,8 +3615,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (mClosingApps.size() > 0) { pw.print(" mClosingApps="); pw.println(mClosingApps); } - if (mChangingApps.size() > 0) { - pw.print(" mChangingApps="); pw.println(mChangingApps); + if (mChangingContainers.size() > 0) { + pw.print(" mChangingApps="); pw.println(mChangingContainers); } } @@ -4085,7 +4025,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInputMonitor.updateInputWindowsLw(false /*force*/); } - mWmService.mH.sendEmptyMessage(UPDATE_DOCKED_STACK_DIVIDER); + mWmService.mH.sendEmptyMessage(UPDATE_MULTI_WINDOW_STACKS); } /** @@ -4693,17 +4633,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo @Override int getOrientation(int candidate) { if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { - // Apps and their containers are not allowed to specify an orientation while the - // docked stack is visible...except for the home stack if the docked stack is - // minimized and it actually set something and the bounds is different from the - // display. + // Apps and their containers are not allowed to specify an orientation while using + // root tasks...except for the home stack if it is not resizable and currently + // visible (top of) its root task. if (mRootHomeTask != null && mRootHomeTask.isVisible() - && mDividerControllerLocked.isMinimizedDock() - && !(mDividerControllerLocked.isHomeStackResizable() - && mRootHomeTask.matchParentBounds())) { - final int orientation = mRootHomeTask.getOrientation(); - if (orientation != SCREEN_ORIENTATION_UNSET) { - return orientation; + && mRootHomeTask.getTile() != null) { + final Task topMost = mRootHomeTask.getTopMostTask(); + final boolean resizable = topMost == null && topMost.isResizeable(); + if (!(resizable && mRootHomeTask.matchParentBounds())) { + final int orientation = mRootHomeTask.getOrientation(); + if (orientation != SCREEN_ORIENTATION_UNSET) { + return orientation; + } } } return SCREEN_ORIENTATION_UNSPECIFIED; @@ -6168,8 +6109,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo t.removeAllChildren(); } } - mDividerControllerLocked.setMinimizedDockedStack(false /* minimized */, - false /* animate */); } finally { final ActivityStack topFullscreenStack = getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index f02a9dd61107..44507390142c 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -25,12 +25,16 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND import static android.content.res.Configuration.UI_MODE_TYPE_CAR; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.view.Display.TYPE_INTERNAL; +import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES; import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT; +import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_LEFT_GESTURES; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; +import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_RIGHT_GESTURES; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_TOP_GESTURES; import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; @@ -1032,7 +1036,9 @@ public class DisplayPolicy { // In Gesture Nav, navigation bar frame is larger than frame to // calculate inset. - if (mNavigationBarPosition == NAV_BAR_BOTTOM) { + if (navigationBarPosition(displayFrames.mDisplayWidth, + displayFrames.mDisplayHeight, + displayFrames.mRotation) == NAV_BAR_BOTTOM) { sTmpRect.set(displayFrames.mUnrestricted); sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe); inOutFrame.top = sTmpRect.bottom @@ -1178,8 +1184,6 @@ public class DisplayPolicy { return R.anim.dock_left_enter; } } - } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) { - return selectDockedDividerAnimation(win, transit); } if (transit == TRANSIT_PREVIEW_DONE) { @@ -1204,36 +1208,6 @@ public class DisplayPolicy { return ANIMATION_STYLEABLE; } - private int selectDockedDividerAnimation(WindowState win, int transit) { - int insets = mDisplayContent.getDockedDividerController().getContentInsets(); - - // If the divider is behind the navigation bar, don't animate. - final Rect frame = win.getFrameLw(); - final boolean behindNavBar = mNavigationBar != null - && ((mNavigationBarPosition == NAV_BAR_BOTTOM - && frame.top + insets >= mNavigationBar.getFrameLw().top) - || (mNavigationBarPosition == NAV_BAR_RIGHT - && frame.left + insets >= mNavigationBar.getFrameLw().left) - || (mNavigationBarPosition == NAV_BAR_LEFT - && frame.right - insets <= mNavigationBar.getFrameLw().right)); - final boolean landscape = frame.height() > frame.width(); - final boolean offscreenLandscape = landscape && (frame.right - insets <= 0 - || frame.left + insets >= win.getDisplayFrameLw().right); - final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0 - || frame.bottom + insets >= win.getDisplayFrameLw().bottom); - final boolean offscreen = offscreenLandscape || offscreenPortrait; - if (behindNavBar || offscreen) { - return ANIMATION_STYLEABLE; - } - if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { - return R.anim.fade_in; - } else if (transit == TRANSIT_EXIT) { - return R.anim.fade_out; - } else { - return ANIMATION_STYLEABLE; - } - } - /** * Called when a new system UI visibility is being reported, allowing * the policy to adjust what is actually reported. @@ -1266,10 +1240,7 @@ public class DisplayPolicy { * most recent layout, so they are not guaranteed to be correct. * * @param attrs The LayoutParams of the window. - * @param taskBounds The bounds of the task this window is on or {@code null} if no task is - * associated with the window. - * @param displayFrames display frames. - * @param floatingStack Whether the window's stack is floating. + * @param windowToken The token of the window. * @param outFrame The frame of the window. * @param outContentInsets The areas covered by system windows, expressed as positive insets. * @param outStableInsets The areas covered by stable system windows irrespective of their @@ -1278,8 +1249,7 @@ public class DisplayPolicy { * @return Whether to always consume the system bars. * See {@link #areSystemBarsForcedShownLw(WindowState)}. */ - public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds, - DisplayFrames displayFrames, boolean floatingStack, Rect outFrame, + boolean getLayoutHint(LayoutParams attrs, WindowToken windowToken, Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout) { final int fl = PolicyControl.getWindowFlags(null, attrs); @@ -1292,6 +1262,18 @@ public class DisplayPolicy { && (fl & FLAG_LAYOUT_INSET_DECOR) != 0; final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0; + final boolean isFixedRotationTransforming = + windowToken != null && windowToken.isFixedRotationTransforming(); + final ActivityRecord activity = windowToken != null ? windowToken.asActivityRecord() : null; + final Task task = activity != null ? activity.getTask() : null; + final Rect taskBounds = isFixedRotationTransforming + // Use token (activity) bounds if it is rotated because its task is not rotated. + ? windowToken.getBounds() + : (task != null ? task.getBounds() : null); + final DisplayFrames displayFrames = isFixedRotationTransforming + ? windowToken.getFixedRotationTransformDisplayFrames() + : mDisplayContent.mDisplayFrames; + if (layoutInScreenAndInsetDecor && !screenDecor) { if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 || (attrs.getFitInsetsTypes() & Type.navigationBars()) == 0) { @@ -1300,15 +1282,10 @@ public class DisplayPolicy { outFrame.set(displayFrames.mRestricted); } - final Rect sf; - if (floatingStack) { - sf = null; - } else { - sf = displayFrames.mStable; - } - + final boolean isFloatingTask = task != null && task.isFloating(); + final Rect sf = isFloatingTask ? null : displayFrames.mStable; final Rect cf; - if (floatingStack) { + if (isFloatingTask) { cf = null; } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) { if ((fl & FLAG_FULLSCREEN) != 0) { @@ -1457,6 +1434,8 @@ public class DisplayPolicy { */ void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) { displayFrames.onBeginLayout(); + updateInsetsStateForDisplayCutout(displayFrames, insetsState); + insetsState.setDisplayFrame(displayFrames.mUnrestricted); final WindowFrames simulatedWindowFrames = new WindowFrames(); if (mNavigationBar != null) { simulateLayoutDecorWindow( @@ -1484,6 +1463,8 @@ public class DisplayPolicy { */ public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) { displayFrames.onBeginLayout(); + updateInsetsStateForDisplayCutout(displayFrames, + mDisplayContent.getInsetsStateController().getRawInsetsState()); mSystemGestures.screenWidth = displayFrames.mUnrestricted.width(); mSystemGestures.screenHeight = displayFrames.mUnrestricted.height(); @@ -1550,6 +1531,23 @@ public class DisplayPolicy { mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation; } + private static void updateInsetsStateForDisplayCutout(DisplayFrames displayFrames, + InsetsState state) { + if (displayFrames.mDisplayCutout.getDisplayCutout().isEmpty()) { + state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT); + state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT); + state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT); + state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT); + return; + } + final Rect u = displayFrames.mUnrestricted; + final Rect s = displayFrames.mDisplayCutoutSafe; + state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(u.left, u.top, s.left, u.bottom); + state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(u.left, u.top, u.right, s.top); + state.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(s.right, u.top, u.right, u.bottom); + state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(u.left, s.bottom, u.right, u.bottom); + } + /** Enforces the last layout policy for display frames. */ private void postAdjustDisplayFrames(DisplayFrames displayFrames) { if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) { diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 958c8ae94e47..20738ed29470 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -16,330 +16,26 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; -import static android.content.res.Configuration.ORIENTATION_PORTRAIT; -import static android.view.Surface.ROTATION_270; -import static android.view.Surface.ROTATION_90; -import static android.view.WindowManager.DOCKED_BOTTOM; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_RIGHT; -import static android.view.WindowManager.DOCKED_TOP; -import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; - -import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION; -import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR; -import static com.android.server.wm.DockedStackDividerControllerProto.MINIMIZED_DOCK; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - -import android.content.Context; -import android.content.res.Configuration; import android.graphics.Rect; -import android.os.RemoteCallbackList; -import android.os.RemoteException; -import android.util.ArraySet; -import android.util.Slog; -import android.util.proto.ProtoOutputStream; -import android.view.DisplayCutout; -import android.view.DisplayInfo; -import android.view.IDockedStackListener; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; -import android.view.animation.PathInterpolator; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.inputmethod.SoftInputShowHideReason; -import com.android.internal.policy.DividerSnapAlgorithm; -import com.android.internal.policy.DockedDividerUtils; -import com.android.server.LocalServices; -import com.android.server.inputmethod.InputMethodManagerInternal; -import com.android.server.wm.WindowManagerService.H; - -import java.io.PrintWriter; /** * Keeps information about the docked stack divider. */ public class DockedStackDividerController { - private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM; - - /** - * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip - * revealing surface at the earliest. - */ - private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f; - - /** - * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip - * revealing surface at the latest. - */ - private static final float CLIP_REVEAL_MEET_LAST = 1f; - - /** - * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start - * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}. - */ - private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f; - - /** - * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, - * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}. - */ - private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f; - - private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR = - new PathInterpolator(0.2f, 0f, 0.1f, 1f); - - private static final long IME_ADJUST_ANIM_DURATION = 280; - - private static final long IME_ADJUST_DRAWN_TIMEOUT = 200; - - private static final int DIVIDER_WIDTH_INACTIVE_DP = 4; - - private final WindowManagerService mService; private final DisplayContent mDisplayContent; - private int mDividerWindowWidth; - private int mDividerWindowWidthInactive; - private int mDividerInsets; - private int mTaskHeightInMinimizedMode; private boolean mResizing; - private WindowState mWindow; - private final Rect mTmpRect = new Rect(); - private final Rect mTmpRect2 = new Rect(); - private final Rect mTmpRect3 = new Rect(); - private final Rect mLastRect = new Rect(); - private boolean mLastVisibility = false; - private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners - = new RemoteCallbackList<>(); - private boolean mMinimizedDock; - private int mOriginalDockedSide = DOCKED_INVALID; - private boolean mAnimatingForMinimizedDockedStack; - private boolean mAnimationStarted; - private long mAnimationStartTime; - private float mAnimationStart; - private float mAnimationTarget; - private long mAnimationDuration; - private boolean mAnimationStartDelayed; - private final Interpolator mMinimizedDockInterpolator; - private float mMaximizeMeetFraction; private final Rect mTouchRegion = new Rect(); - private boolean mAnimatingForIme; - private boolean mAdjustedForIme; - private int mImeHeight; - private WindowState mDelayedImeWin; - private boolean mAdjustedForDivider; - private float mDividerAnimationStart; - private float mDividerAnimationTarget; - float mLastAnimationProgress; - float mLastDividerProgress; - private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4]; - private boolean mImeHideRequested; - private ActivityStack mDimmedStack; - DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) { - mService = service; + DockedStackDividerController(DisplayContent displayContent) { mDisplayContent = displayContent; - final Context context = service.mContext; - mMinimizedDockInterpolator = AnimationUtils.loadInterpolator( - context, android.R.interpolator.fast_out_slow_in); - loadDimens(); - } - - int getSmallestWidthDpForBounds(Rect bounds) { - final DisplayInfo di = mDisplayContent.getDisplayInfo(); - - final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth; - final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight; - int minWidth = Integer.MAX_VALUE; - - // Go through all screen orientations and find the orientation in which the task has the - // smallest width. - for (int rotation = 0; rotation < 4; rotation++) { - mTmpRect.set(bounds); - mDisplayContent.rotateBounds(di.rotation, rotation, mTmpRect); - final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); - mTmpRect2.set(0, 0, - rotated ? baseDisplayHeight : baseDisplayWidth, - rotated ? baseDisplayWidth : baseDisplayHeight); - final int orientation = mTmpRect2.width() <= mTmpRect2.height() - ? ORIENTATION_PORTRAIT - : ORIENTATION_LANDSCAPE; - final int dockSide = getDockSide(mTmpRect, mTmpRect2, orientation, rotation); - final int position = DockedDividerUtils.calculatePositionForBounds(mTmpRect, dockSide, - getContentWidth()); - - final DisplayCutout displayCutout = mDisplayContent.calculateDisplayCutoutForRotation( - rotation).getDisplayCutout(); - - // Since we only care about feasible states, snap to the closest snap target, like it - // would happen when actually rotating the screen. - final int snappedPosition = mSnapAlgorithmForRotation[rotation] - .calculateNonDismissingSnapTarget(position).position; - DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect, - mTmpRect2.width(), mTmpRect2.height(), getContentWidth()); - mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, mTmpRect2.width(), - mTmpRect2.height(), displayCutout, mTmpRect3); - mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect); - minWidth = Math.min(mTmpRect.width(), minWidth); - } - return (int) (minWidth / mDisplayContent.getDisplayMetrics().density); - } - - /** - * Get the current docked side. Determined by its location of {@param bounds} within - * {@param displayRect} but if both are the same, it will try to dock to each side and determine - * if allowed in its respected {@param orientation}. - * - * @param bounds bounds of the docked task to get which side is docked - * @param displayRect bounds of the display that contains the docked task - * @param orientation the origination of device - * @return current docked side - */ - int getDockSide(Rect bounds, Rect displayRect, int orientation, int rotation) { - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - // Portrait mode, docked either at the top or the bottom. - final int diff = (displayRect.bottom - bounds.bottom) - (bounds.top - displayRect.top); - if (diff > 0) { - return DOCKED_TOP; - } else if (diff < 0) { - return DOCKED_BOTTOM; - } - return canPrimaryStackDockTo(DOCKED_TOP, displayRect, rotation) - ? DOCKED_TOP : DOCKED_BOTTOM; - } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - // Landscape mode, docked either on the left or on the right. - final int diff = (displayRect.right - bounds.right) - (bounds.left - displayRect.left); - if (diff > 0) { - return DOCKED_LEFT; - } else if (diff < 0) { - return DOCKED_RIGHT; - } - return canPrimaryStackDockTo(DOCKED_LEFT, displayRect, rotation) - ? DOCKED_LEFT : DOCKED_RIGHT; - } - return DOCKED_INVALID; - } - - void getHomeStackBoundsInDockedMode(Configuration parentConfig, int dockSide, Rect outBounds) { - final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout; - final int displayWidth = parentConfig.windowConfiguration.getBounds().width(); - final int displayHeight = parentConfig.windowConfiguration.getBounds().height(); - mDisplayContent.getDisplayPolicy().getStableInsetsLw( - parentConfig.windowConfiguration.getRotation(), displayWidth, displayHeight, - displayCutout, mTmpRect); - int dividerSize = mDividerWindowWidth - 2 * mDividerInsets; - // The offset in the left (landscape)/top (portrait) is calculated with the minimized - // offset value with the divider size and any system insets in that direction. - if (parentConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { - outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top, - displayWidth, displayHeight); - } else { - // In landscape also inset the left/right side with the status bar height to match the - // minimized size height in portrait mode. - final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top; - int left = mTmpRect.left; - int right = displayWidth - mTmpRect.right; - if (dockSide == DOCKED_LEFT) { - left += primaryTaskWidth; - } else if (dockSide == DOCKED_RIGHT) { - right -= primaryTaskWidth; - } - outBounds.set(left, 0, right, displayHeight); - } - } - - boolean isHomeStackResizable() { - final ActivityStack homeStack = mDisplayContent.getRootHomeTask(); - if (homeStack == null) { - return false; - } - final Task homeTask = homeStack.getTopMostTask(); - return homeTask != null && homeTask.isResizeable(); - } - - private void initSnapAlgorithmForRotations() { - final Configuration baseConfig = mDisplayContent.getConfiguration(); - - // Initialize the snap algorithms for all 4 screen orientations. - final Configuration config = new Configuration(); - for (int rotation = 0; rotation < 4; rotation++) { - final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); - final int dw = rotated - ? mDisplayContent.mBaseDisplayHeight - : mDisplayContent.mBaseDisplayWidth; - final int dh = rotated - ? mDisplayContent.mBaseDisplayWidth - : mDisplayContent.mBaseDisplayHeight; - final DisplayCutout displayCutout = - mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout(); - final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); - displayPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect); - config.unset(); - config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; - - final int appWidth = displayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, - baseConfig.uiMode, displayCutout); - final int appHeight = displayPolicy.getNonDecorDisplayHeight(dw, dh, rotation, - baseConfig.uiMode, displayCutout); - displayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect); - final int leftInset = mTmpRect.left; - final int topInset = mTmpRect.top; - - config.windowConfiguration.setAppBounds(leftInset /*left*/, topInset /*top*/, - leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/); - - final float density = mDisplayContent.getDisplayMetrics().density; - config.screenWidthDp = (int) (displayPolicy.getConfigDisplayWidth(dw, dh, rotation, - baseConfig.uiMode, displayCutout) / density); - config.screenHeightDp = (int) (displayPolicy.getConfigDisplayHeight(dw, dh, rotation, - baseConfig.uiMode, displayCutout) / density); - final Context rotationContext = mService.mContext.createConfigurationContext(config); - mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm( - rotationContext.getResources(), dw, dh, getContentWidth(), - config.orientation == ORIENTATION_PORTRAIT, mTmpRect); - } - } - - private void loadDimens() { - final Context context = mService.mContext; - mDividerWindowWidth = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.docked_stack_divider_thickness); - mDividerInsets = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.docked_stack_divider_insets); - mDividerWindowWidthInactive = WindowManagerService.dipToPixel( - DIVIDER_WIDTH_INACTIVE_DP, mDisplayContent.getDisplayMetrics()); - mTaskHeightInMinimizedMode = context.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.task_height_of_minimized_mode); - initSnapAlgorithmForRotations(); - } - - void onConfigurationChanged() { - loadDimens(); } boolean isResizing() { return mResizing; } - int getContentWidth() { - return mDividerWindowWidth - 2 * mDividerInsets; - } - - int getContentInsets() { - return mDividerInsets; - } - - int getContentWidthInactive() { - return mDividerWindowWidthInactive; - } - void setResizing(boolean resizing) { if (mResizing != resizing) { mResizing = resizing; @@ -353,676 +49,10 @@ public class DockedStackDividerController { void getTouchRegion(Rect outRegion) { outRegion.set(mTouchRegion); - if (mWindow != null) { - outRegion.offset(mWindow.getFrameLw().left, mWindow.getFrameLw().top); - } } private void resetDragResizingChangeReported() { mDisplayContent.forAllWindows(WindowState::resetDragResizingChangeReported, true /* traverseTopToBottom */ ); } - - void setWindow(WindowState window) { - mWindow = window; - reevaluateVisibility(false); - } - - void reevaluateVisibility(boolean force) { - if (mWindow == null) { - return; - } - ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask(); - - // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide - final boolean visible = stack != null; - if (mLastVisibility == visible && !force) { - return; - } - mLastVisibility = visible; - notifyDockedDividerVisibilityChanged(visible); - if (!visible) { - setResizeDimLayer(false, WINDOWING_MODE_UNDEFINED, 0f); - } - } - - private boolean wasVisible() { - return mLastVisibility; - } - - void setAdjustedForIme( - boolean adjustedForIme, boolean adjustedForDivider, - boolean animate, WindowState imeWin, int imeHeight) { - if (mAdjustedForIme != adjustedForIme || (adjustedForIme && mImeHeight != imeHeight) - || mAdjustedForDivider != adjustedForDivider) { - if (animate && !mAnimatingForMinimizedDockedStack) { - // Notify SystemUI to set the target docked stack size according current docked - // state without animation when calling startImeAdjustAnimation. - notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */, - isHomeStackResizable()); - startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin); - } else { - // Animation might be delayed, so only notify if we don't run an animation. - notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */); - } - mAdjustedForIme = adjustedForIme; - mImeHeight = imeHeight; - mAdjustedForDivider = adjustedForDivider; - } - } - - int getImeHeightAdjustedFor() { - return mImeHeight; - } - - void positionDockedStackedDivider(Rect frame) { - ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask(); - if (stack == null) { - // Unfortunately we might end up with still having a divider, even though the underlying - // stack was already removed. This is because we are on AM thread and the removal of the - // divider was deferred to WM thread and hasn't happened yet. In that case let's just - // keep putting it in the same place it was before the stack was removed to have - // continuity and prevent it from jumping to the center. It will get hidden soon. - frame.set(mLastRect); - return; - } else { - stack.getDimBounds(mTmpRect); - } - int side = stack.getDockSide(); - switch (side) { - case DOCKED_LEFT: - frame.set(mTmpRect.right - mDividerInsets, frame.top, - mTmpRect.right + frame.width() - mDividerInsets, frame.bottom); - break; - case DOCKED_TOP: - frame.set(frame.left, mTmpRect.bottom - mDividerInsets, - mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets); - break; - case DOCKED_RIGHT: - frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top, - mTmpRect.left + mDividerInsets, frame.bottom); - break; - case DOCKED_BOTTOM: - frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets, - frame.right, mTmpRect.top + mDividerInsets); - break; - } - mLastRect.set(frame); - } - - private void notifyDockedDividerVisibilityChanged(boolean visible) { - final int size = mDockedStackListeners.beginBroadcast(); - for (int i = 0; i < size; ++i) { - final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); - try { - listener.onDividerVisibilityChanged(visible); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e); - } - } - mDockedStackListeners.finishBroadcast(); - } - - /** - * Checks if the primary stack is allowed to dock to a specific side based on its original dock - * side. - * - * @param dockSide the side to see if it is valid - * @return true if the side provided is valid - */ - boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) { - final DisplayPolicy policy = mDisplayContent.getDisplayPolicy(); - return isDockSideAllowed(dockSide, mOriginalDockedSide, - policy.navigationBarPosition(parentRect.width(), parentRect.height(), rotation), - policy.navigationBarCanMove()); - } - - @VisibleForTesting - static boolean isDockSideAllowed(int dockSide, int originalDockSide, int navBarPosition, - boolean navigationBarCanMove) { - if (dockSide == DOCKED_TOP) { - return true; - } - - if (navigationBarCanMove) { - // Only allow the dockside opposite to the nav bar position in landscape - return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT - || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT; - } - - // Side is the same as original side - if (dockSide == originalDockSide) { - return true; - } - - // Only if original docked side was top in portrait will allow left for landscape - return dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP; - } - - void notifyDockedStackExistsChanged(boolean exists) { - // TODO(multi-display): Perform all actions only for current display. - final int size = mDockedStackListeners.beginBroadcast(); - for (int i = 0; i < size; ++i) { - final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); - try { - listener.onDockedStackExistsChanged(exists); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e); - } - } - mDockedStackListeners.finishBroadcast(); - if (exists) { - InputMethodManagerInternal inputMethodManagerInternal = - LocalServices.getService(InputMethodManagerInternal.class); - if (inputMethodManagerInternal != null) { - - // Hide the current IME to avoid problems with animations from IME adjustment when - // attaching the docked stack. - inputMethodManagerInternal.hideCurrentInputMethod( - SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED); - mImeHideRequested = true; - } - - // If a primary stack was just created, it will not have access to display content at - // this point so pass it from here to get a valid dock side. - final ActivityStack stack = - mDisplayContent.getRootSplitScreenPrimaryTask(); - mOriginalDockedSide = stack.getDockSideForDisplay(mDisplayContent); - return; - } - mOriginalDockedSide = DOCKED_INVALID; - setMinimizedDockedStack(false /* minimizedDock */, false /* animate */); - - if (mDimmedStack != null) { - mDimmedStack.stopDimming(); - mDimmedStack = null; - } - } - - /** - * Resets the state that IME hide has been requested. See {@link #isImeHideRequested}. - */ - void resetImeHideRequested() { - mImeHideRequested = false; - } - - /** - * The docked stack divider controller makes sure the IME gets hidden when attaching the docked - * stack, to avoid animation problems. This flag indicates whether the request to hide the IME - * has been sent in an asynchronous manner, and the IME should be treated as hidden already. - * - * @return whether IME hide request has been sent - */ - boolean isImeHideRequested() { - return mImeHideRequested; - } - - private void notifyDockedStackMinimizedChanged(boolean minimizedDock, boolean animate, - boolean isHomeStackResizable) { - long animDuration = 0; - if (animate) { - final ActivityStack stack = - mDisplayContent.getRootSplitScreenPrimaryTask(); - final long transitionDuration = isAnimationMaximizing() - ? mDisplayContent.mAppTransition.getLastClipRevealTransitionDuration() - : DEFAULT_APP_TRANSITION_DURATION; - mAnimationDuration = (long) - (transitionDuration * mService.getTransitionAnimationScaleLocked()); - mMaximizeMeetFraction = getClipRevealMeetFraction(stack); - animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction); - } - final int size = mDockedStackListeners.beginBroadcast(); - for (int i = 0; i < size; ++i) { - final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); - try { - listener.onDockedStackMinimizedChanged(minimizedDock, animDuration, - isHomeStackResizable); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e); - } - } - mDockedStackListeners.finishBroadcast(); - // Only notify ATM after we update the remote listeners, otherwise it may trigger another - // minimize change, which would lead to an inversion of states send to the listeners - mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock); - } - - void notifyDockSideChanged(int newDockSide) { - final int size = mDockedStackListeners.beginBroadcast(); - for (int i = 0; i < size; ++i) { - final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); - try { - listener.onDockSideChanged(newDockSide); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering dock side changed event.", e); - } - } - mDockedStackListeners.finishBroadcast(); - } - - private void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) { - final int size = mDockedStackListeners.beginBroadcast(); - for (int i = 0; i < size; ++i) { - final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); - try { - listener.onAdjustedForImeChanged(adjustedForIme, animDuration); - } catch (RemoteException e) { - Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e); - } - } - mDockedStackListeners.finishBroadcast(); - } - - void registerDockedStackListener(IDockedStackListener listener) { - mDockedStackListeners.register(listener); - notifyDockedDividerVisibilityChanged(wasVisible()); - notifyDockedStackExistsChanged( - mDisplayContent.getRootSplitScreenPrimaryTask() != null); - notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */, - isHomeStackResizable()); - notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */); - - } - - /** - * Shows a dim layer with {@param alpha} if {@param visible} is true and - * {@param targetWindowingMode} isn't - * {@link android.app.WindowConfiguration#WINDOWING_MODE_UNDEFINED} and there is a stack on the - * display in that windowing mode. - */ - void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) { - // TODO: Maybe only allow split-screen windowing modes? - final ActivityStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED - ? mDisplayContent.getTopStackInWindowingMode(targetWindowingMode) - : null; - final ActivityStack dockedStack = mDisplayContent.getRootSplitScreenPrimaryTask(); - boolean visibleAndValid = visible && stack != null && dockedStack != null; - - // Ensure an old dim that was shown for the docked stack divider is removed so we don't end - // up with dim layers that can no longer be removed. - if (mDimmedStack != null && mDimmedStack != stack) { - mDimmedStack.stopDimming(); - mDimmedStack = null; - } - - if (visibleAndValid) { - mDimmedStack = stack; - stack.dim(alpha); - } - if (!visibleAndValid && stack != null) { - mDimmedStack = null; - stack.stopDimming(); - } - } - - /** - * Notifies the docked stack divider controller of a visibility change that happens without - * an animation. - */ - void notifyAppVisibilityChanged() { - checkMinimizeChanged(false /* animate */); - } - - void notifyAppTransitionStarting(ArraySet<ActivityRecord> openingApps, int appTransition) { - final boolean wasMinimized = mMinimizedDock; - checkMinimizeChanged(true /* animate */); - - // We were minimized, and now we are still minimized, but somebody is trying to launch an - // app in docked stack, better show recent apps so we actually get unminimized! However do - // not do this if keyguard is dismissed such as when the device is unlocking. This catches - // any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because - // we couldn't retrace the launch of the app in the docked stack to the launch from - // homescreen. - if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps) - && appTransition != TRANSIT_NONE && - !AppTransition.isKeyguardGoingAwayTransit(appTransition)) { - if (mService.mAtmInternal.isRecentsComponentHomeActivity(mService.mCurrentUserId)) { - // When the home activity is the recents component and we are already minimized, - // then there is nothing to do here since home is already visible - } else { - mService.showRecentApps(); - } - } - } - - /** - * @return true if {@param apps} contains an activity in the docked stack, false otherwise. - */ - private boolean containsAppInDockedStack(ArraySet<ActivityRecord> apps) { - for (int i = apps.size() - 1; i >= 0; i--) { - final ActivityRecord activity = apps.valueAt(i); - if (activity.getTask() != null && activity.inSplitScreenPrimaryWindowingMode()) { - return true; - } - } - return false; - } - - boolean isMinimizedDock() { - return mMinimizedDock; - } - - void checkMinimizeChanged(boolean animate) { - if (mDisplayContent.getRootSplitScreenPrimaryTask() == null) { - return; - } - final ActivityStack homeStack = mDisplayContent.getRootHomeTask(); - if (homeStack == null) { - return; - } - final Task homeTask = homeStack.getTopMostTask(); - if (homeTask == null || !isWithinDisplay(homeTask)) { - return; - } - - // Do not minimize when dock is already minimized while keyguard is showing and not - // occluded such as unlocking the screen - if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) { - return; - } - final ActivityStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode( - WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController(); - final boolean minimizedForRecentsAnimation = recentsAnim != null && - recentsAnim.isSplitScreenMinimized(); - boolean homeVisible = homeTask.getTopVisibleActivity() != null; - if (homeVisible && topSecondaryStack != null) { - // Home should only be considered visible if it is greater or equal to the top secondary - // stack in terms of z-order. - homeVisible = homeStack.compareTo(topSecondaryStack) >= 0; - } - setMinimizedDockedStack(homeVisible || minimizedForRecentsAnimation, animate); - } - - private boolean isWithinDisplay(Task task) { - task.getBounds(mTmpRect); - mDisplayContent.getBounds(mTmpRect2); - return mTmpRect.intersect(mTmpRect2); - } - - /** - * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the - * docked stack are heavily clipped so you can only see a minimal peek state. - * - * @param minimizedDock Whether the docked stack is currently minimized. - * @param animate Whether to animate the change. - */ - void setMinimizedDockedStack(boolean minimizedDock, boolean animate) { - final boolean wasMinimized = mMinimizedDock; - mMinimizedDock = minimizedDock; - if (minimizedDock == wasMinimized) { - return; - } - - final boolean imeChanged = clearImeAdjustAnimation(); - boolean minimizedChange = false; - if (isHomeStackResizable()) { - notifyDockedStackMinimizedChanged(minimizedDock, animate, - true /* isHomeStackResizable */); - minimizedChange = true; - } else { - if (minimizedDock) { - if (animate) { - startAdjustAnimation(0f, 1f); - } else { - minimizedChange |= setMinimizedDockedStack(true); - } - } else { - if (animate) { - startAdjustAnimation(1f, 0f); - } else { - minimizedChange |= setMinimizedDockedStack(false); - } - } - } - if (imeChanged || minimizedChange) { - if (imeChanged && !minimizedChange) { - Slog.d(TAG, "setMinimizedDockedStack: IME adjust changed due to minimizing," - + " minimizedDock=" + minimizedDock - + " minimizedChange=" + minimizedChange); - } - mService.mWindowPlacerLocked.performSurfacePlacement(); - } - } - - private boolean clearImeAdjustAnimation() { - final boolean changed = mDisplayContent.clearImeAdjustAnimation(); - mAnimatingForIme = false; - return changed; - } - - private void startAdjustAnimation(float from, float to) { - mAnimatingForMinimizedDockedStack = true; - mAnimationStarted = false; - mAnimationStart = from; - mAnimationTarget = to; - } - - private void startImeAdjustAnimation( - boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) { - - // If we're not in an animation, the starting point depends on whether we're adjusted - // or not. If we're already in an animation, we start from where the current animation - // left off, so that the motion doesn't look discontinuous. - if (!mAnimatingForIme) { - mAnimationStart = mAdjustedForIme ? 1 : 0; - mDividerAnimationStart = mAdjustedForDivider ? 1 : 0; - mLastAnimationProgress = mAnimationStart; - mLastDividerProgress = mDividerAnimationStart; - } else { - mAnimationStart = mLastAnimationProgress; - mDividerAnimationStart = mLastDividerProgress; - } - mAnimatingForIme = true; - mAnimationStarted = false; - mAnimationTarget = adjustedForIme ? 1 : 0; - mDividerAnimationTarget = adjustedForDivider ? 1 : 0; - - mDisplayContent.beginImeAdjustAnimation(); - - // We put all tasks into drag resizing mode - wait until all of them have completed the - // drag resizing switch. - final Runnable existingWaitingForDrwanCallback = - mService.mWaitingForDrawnCallbacks.get(mService.mRoot); - if (existingWaitingForDrwanCallback != null) { - mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, mService.mRoot); - mService.mH.sendMessageDelayed(mService.mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, - mService.mRoot), - IME_ADJUST_DRAWN_TIMEOUT); - mAnimationStartDelayed = true; - if (imeWin != null) { - - // There might be an old window delaying the animation start - clear it. - if (mDelayedImeWin != null) { - mDelayedImeWin.endDelayingAnimationStart(); - } - mDelayedImeWin = imeWin; - imeWin.startDelayingAnimationStart(); - } - - // If we are already waiting for something to be drawn, clear out the old one so it - // still gets executed. - // TODO: Have a real system where we can wait on different windows to be drawn with - // different callbacks. - existingWaitingForDrwanCallback.run(); - mService.mWaitingForDrawnCallbacks.put(mService.mRoot, () -> { - synchronized (mService.mGlobalLock) { - mAnimationStartDelayed = false; - if (mDelayedImeWin != null) { - mDelayedImeWin.endDelayingAnimationStart(); - } - // If the adjust status changed since this was posted, only notify - // the new states and don't animate. - long duration = 0; - if (mAdjustedForIme == adjustedForIme - && mAdjustedForDivider == adjustedForDivider) { - duration = IME_ADJUST_ANIM_DURATION; - } else { - Slog.w(TAG, "IME adjust changed while waiting for drawn:" - + " adjustedForIme=" + adjustedForIme - + " adjustedForDivider=" + adjustedForDivider - + " mAdjustedForIme=" + mAdjustedForIme - + " mAdjustedForDivider=" + mAdjustedForDivider); - } - notifyAdjustedForImeChanged( - mAdjustedForIme || mAdjustedForDivider, duration); - } - }); - } else { - notifyAdjustedForImeChanged( - adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION); - } - } - - private boolean setMinimizedDockedStack(boolean minimized) { - final ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask(); - notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable()); - return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f); - } - - private boolean isAnimationMaximizing() { - return mAnimationTarget == 0f; - } - - public boolean animate(long now) { - if (mWindow == null) { - return false; - } - if (mAnimatingForMinimizedDockedStack) { - return animateForMinimizedDockedStack(now); - } else if (mAnimatingForIme && !mDisplayContent.mAppTransition.isRunning()) { - // To prevent task stack resize animation may flicking when playing app transition - // animation & IME window enter animation in parallel, make sure app transition is done - // and then start to animate for IME. - return animateForIme(now); - } - return false; - } - - private boolean animateForIme(long now) { - if (!mAnimationStarted || mAnimationStartDelayed) { - mAnimationStarted = true; - mAnimationStartTime = now; - mAnimationDuration = (long) - (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked()); - } - float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration); - t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR) - .getInterpolation(t); - final boolean updated = - mDisplayContent.animateForIme(t, mAnimationTarget, mDividerAnimationTarget); - if (updated) { - mService.mWindowPlacerLocked.performSurfacePlacement(); - } - if (t >= 1.0f) { - mLastAnimationProgress = mAnimationTarget; - mLastDividerProgress = mDividerAnimationTarget; - mAnimatingForIme = false; - return false; - } else { - return true; - } - } - - private boolean animateForMinimizedDockedStack(long now) { - final ActivityStack stack = mDisplayContent.getRootSplitScreenPrimaryTask(); - if (!mAnimationStarted) { - mAnimationStarted = true; - mAnimationStartTime = now; - notifyDockedStackMinimizedChanged(mMinimizedDock, true /* animate */, - isHomeStackResizable() /* isHomeStackResizable */); - } - float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration); - t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator) - .getInterpolation(t); - if (stack != null) { - if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) { - mService.mWindowPlacerLocked.performSurfacePlacement(); - } - } - if (t >= 1.0f) { - mAnimatingForMinimizedDockedStack = false; - return false; - } else { - return true; - } - } - - float getInterpolatedAnimationValue(float t) { - return t * mAnimationTarget + (1 - t) * mAnimationStart; - } - - float getInterpolatedDividerValue(float t) { - return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart; - } - - /** - * Gets the amount how much to minimize a stack depending on the interpolated fraction t. - */ - private float getMinimizeAmount(ActivityStack stack, float t) { - final float naturalAmount = getInterpolatedAnimationValue(t); - if (isAnimationMaximizing()) { - return adjustMaximizeAmount(stack, t, naturalAmount); - } else { - return naturalAmount; - } - } - - /** - * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount - * during the transition such that the edge of the clip reveal rect is met earlier in the - * transition so we don't create a visible "hole", but only if both the clip reveal and the - * docked stack divider start from about the same portion on the screen. - */ - private float adjustMaximizeAmount(ActivityStack stack, float t, float naturalAmount) { - if (mMaximizeMeetFraction == 1f) { - return naturalAmount; - } - final int minimizeDistance = stack.getMinimizeDistance(); - final float startPrime = mDisplayContent.mAppTransition.getLastClipRevealMaxTranslation() - / (float) minimizeDistance; - final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime; - final float t2 = Math.min(t / mMaximizeMeetFraction, 1); - return amountPrime * t2 + naturalAmount * (1 - t2); - } - - /** - * Retrieves the animation fraction at which the docked stack has to meet the clip reveal - * edge. See {@link #adjustMaximizeAmount}. - */ - private float getClipRevealMeetFraction(ActivityStack stack) { - if (!isAnimationMaximizing() || stack == null || - !mDisplayContent.mAppTransition.hadClipRevealAnimation()) { - return 1f; - } - final int minimizeDistance = stack.getMinimizeDistance(); - final float fraction = Math.abs(mDisplayContent.mAppTransition - .getLastClipRevealMaxTranslation()) / (float) minimizeDistance; - final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN) - / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN))); - return CLIP_REVEAL_MEET_EARLIEST - + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST); - } - - public String toShortString() { - return TAG; - } - - WindowState getWindow() { - return mWindow; - } - - void dump(String prefix, PrintWriter pw) { - pw.println(prefix + "DockedStackDividerController"); - pw.println(prefix + " mLastVisibility=" + mLastVisibility); - pw.println(prefix + " mMinimizedDock=" + mMinimizedDock); - pw.println(prefix + " mAdjustedForIme=" + mAdjustedForIme); - pw.println(prefix + " mAdjustedForDivider=" + mAdjustedForDivider); - } - - void dumpDebug(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - proto.write(MINIMIZED_DOCK, mMinimizedDock); - proto.end(token); - } } diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index b663336bb7ba..f6bf39739cb8 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -20,6 +20,8 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.view.InsetsController.ANIMATION_TYPE_HIDE; +import static android.view.InsetsController.ANIMATION_TYPE_SHOW; import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN; import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; @@ -354,7 +356,8 @@ class InsetsPolicy { mListener, typesReady, this, mListener.getDurationMs(), InsetsController.INTERPOLATOR, true, show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN - : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN); + : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN, + show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE); SurfaceAnimationThread.getHandler().post( () -> mListener.onReady(mAnimationControl, typesReady)); } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 0d3f6b98f483..58aefdc0e547 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -190,7 +190,10 @@ class InsetsSourceProvider { /** @return A new source computed by the specified window frame in the given display frames. */ InsetsSource createSimulatedSource(DisplayFrames displayFrames, WindowFrames windowFrames) { - final InsetsSource source = new InsetsSource(mSource); + // Don't copy visible frame because it might not be calculated in the provided display + // frames and it is not significant for this usage. + final InsetsSource source = new InsetsSource(mSource.getType()); + source.setVisible(mSource.isVisible()); mTmpRect.set(windowFrames.mFrame); if (mFrameProvider != null) { mFrameProvider.accept(displayFrames, mWin, mTmpRect); diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index e69551a0fde4..54cea938b57b 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -125,10 +125,6 @@ public class RecentsAnimationController implements DeathRecipient { // enabled for it to start intercepting touch events. private boolean mInputConsumerEnabled; - // Whether or not the recents animation should cause the primary split-screen stack to be - // minimized - private boolean mSplitScreenMinimized; - private final Rect mTmpRect = new Rect(); private boolean mLinkedToDeathOfRunner; @@ -277,23 +273,6 @@ public class RecentsAnimationController implements DeathRecipient { } @Override - public void setSplitScreenMinimized(boolean minimized) { - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mService.getWindowManagerLock()) { - if (mCanceled) { - return; - } - - mSplitScreenMinimized = minimized; - mService.checkSplitScreenMinimizedChanged(true /* animate */); - } - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override public void hideCurrentInputMethod() { final long token = Binder.clearCallingIdentity(); try { @@ -500,7 +479,7 @@ public class RecentsAnimationController implements DeathRecipient { } if (mTargetActivityRecord != null) { - final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>(1); + final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>(1); reasons.put(mTargetActivityRecord, APP_TRANSITION_RECENTS_ANIM); mService.mAtmService.mStackSupervisor.getActivityMetricsLogger() .notifyTransitionStarting(reasons); @@ -738,10 +717,6 @@ public class RecentsAnimationController implements DeathRecipient { } } - boolean isSplitScreenMinimized() { - return mSplitScreenMinimized; - } - boolean isWallpaperVisible(WindowState w) { return w != null && w.mAttrs.type == TYPE_BASE_APPLICATION && ((w.mActivityRecord != null && mTargetActivityRecord == w.mActivityRecord) @@ -944,7 +919,6 @@ public class RecentsAnimationController implements DeathRecipient { pw.print(innerPrefix); pw.println("mPendingAnimations=" + mPendingAnimations.size()); pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled); pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled); - pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized); pw.print(innerPrefix); pw.println("mTargetActivityRecord=" + mTargetActivityRecord); pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper()); pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition=" diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index d2dbab841f16..0eb9daf26d47 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -387,7 +387,7 @@ class RemoteAnimationController implements DeathRecipient { final ActivityRecord topActivity = mWindowContainer.getTopMostActivity(); if (dc.mOpeningApps.contains(topActivity)) { return RemoteAnimationTarget.MODE_OPENING; - } else if (dc.mChangingApps.contains(topActivity)) { + } else if (dc.mChangingContainers.contains(topActivity)) { return RemoteAnimationTarget.MODE_CHANGING; } else { return RemoteAnimationTarget.MODE_CLOSING; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 64d7db26cd7e..ada5685e6817 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -258,9 +258,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> */ final ArrayList<ActivityTaskManagerInternal.SleepToken> mSleepTokens = new ArrayList<>(); - /** Is dock currently minimized. */ - boolean mIsDockMinimized; - /** Set when a power hint has started, but not ended. */ private boolean mPowerHintSent; @@ -1011,9 +1008,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Send any pending task-info changes that were queued-up during a layout deferment mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges(); - if (DEBUG_WINDOW_TRACE) Slog.e(TAG, - "performSurfacePlacementInner exit: animating=" - + mWmService.mAnimator.isAnimating()); + if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit"); } private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) { @@ -1989,8 +1984,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // We dismiss the docked stack whenever we switch users. final ActivityStack dockedStack = getDefaultDisplay().getRootSplitScreenPrimaryTask(); if (dockedStack != null) { - mStackSupervisor.moveTasksToFullscreenStackLocked( - dockedStack, dockedStack.isFocusedStackOnDisplay()); + getDefaultDisplay().onSplitScreenModeDismissed(); } // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will // also cause all tasks to be moved to the fullscreen stack at a position that is @@ -2167,21 +2161,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - void setDockedStackMinimized(boolean minimized) { - // Get currently focused stack before setting mIsDockMinimized. We do this because if - // split-screen is active, primary stack will not be focusable (see #isFocusable) while - // still occluding other stacks. This will cause getTopDisplayFocusedStack() to return null. - final ActivityStack current = getTopDisplayFocusedStack(); - mIsDockMinimized = minimized; - if (mIsDockMinimized) { - if (current.inSplitScreenPrimaryWindowingMode()) { - // The primary split-screen stack can't be focused while it is minimize, so move - // focus to something else. - current.adjustFocusToNextFocusableStack("setDockedStackMinimized"); - } - } - } - ActivityRecord findTask(ActivityRecord r, int preferredDisplayId) { if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r); mTmpFindTaskResult.clear(); diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index f6cdac5d4565..68975b9d2abd 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -205,7 +205,7 @@ class ScreenRotationAnimation { SurfaceControl.ScreenshotGraphicBuffer gb = mService.mDisplayManagerInternal.screenshot(displayId); if (gb != null) { - mStartLuma = RotationAnimationUtils.getAvgBorderLuma(gb.getGraphicBuffer(), + mStartLuma = RotationAnimationUtils.getMedianBorderLuma(gb.getGraphicBuffer(), gb.getColorSpace()); try { surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(), diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 7164cd85230b..1e54e69c0635 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -128,7 +128,8 @@ class SurfaceAnimator { */ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, @AnimationType int type, - @Nullable OnAnimationFinishedCallback animationFinishedCallback) { + @Nullable OnAnimationFinishedCallback animationFinishedCallback, + @Nullable SurfaceFreezer freezer) { cancelAnimation(t, true /* restarting */, true /* forwardCancel */); mAnimation = anim; mAnimationType = type; @@ -139,9 +140,14 @@ class SurfaceAnimator { cancelAnimation(); return; } - mLeash = createAnimationLeash(surface, t, - mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden); - mAnimatable.onAnimationLeashCreated(t, mLeash); + mLeash = freezer != null ? freezer.takeLeashForAnimation() : null; + if (mLeash == null) { + mLeash = createAnimationLeash(mAnimatable, surface, t, + mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */, + 0 /* y */, hidden); + mAnimatable.onAnimationLeashCreated(t, mLeash); + } + mAnimatable.onLeashAnimationStarting(t, mLeash); if (mAnimationStartDelayed) { if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed"); return; @@ -150,6 +156,12 @@ class SurfaceAnimator { } void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, + @AnimationType int type, + @Nullable OnAnimationFinishedCallback animationFinishedCallback) { + startAnimation(t, anim, hidden, type, animationFinishedCallback, null /* freezer */); + } + + void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, @AnimationType int type) { startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */); } @@ -311,15 +323,31 @@ class SurfaceAnimator { } private void reset(Transaction t, boolean destroyLeash) { - final SurfaceControl surface = mAnimatable.getSurfaceControl(); - final SurfaceControl parent = mAnimatable.getParentSurfaceControl(); + mService.mAnimationTransferMap.remove(mAnimation); + mAnimation = null; + mAnimationFinishedCallback = null; + mAnimationType = ANIMATION_TYPE_NONE; + if (mLeash == null) { + return; + } + SurfaceControl leash = mLeash; + mLeash = null; + final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash); + if (scheduleAnim) { + mService.scheduleAnimationLocked(); + } + } + static boolean removeLeash(Transaction t, Animatable animatable, @NonNull SurfaceControl leash, + boolean destroy) { boolean scheduleAnim = false; + final SurfaceControl surface = animatable.getSurfaceControl(); + final SurfaceControl parent = animatable.getParentSurfaceControl(); // If the surface was destroyed or the leash is invalid, we don't care to reparent it back. // Note that we also set this variable to true even if the parent isn't valid anymore, in // order to ensure onAnimationLeashLost still gets called in this case. - final boolean reparent = mLeash != null && surface != null; + final boolean reparent = surface != null; if (reparent) { if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent: " + parent); // We shouldn't really need these isValid checks but we do @@ -329,40 +357,30 @@ class SurfaceAnimator { scheduleAnim = true; } } - mService.mAnimationTransferMap.remove(mAnimation); - if (mLeash != null && destroyLeash) { - t.remove(mLeash); + if (destroy) { + t.remove(leash); scheduleAnim = true; } - mLeash = null; - mAnimation = null; - mAnimationFinishedCallback = null; - mAnimationType = ANIMATION_TYPE_NONE; if (reparent) { // Make sure to inform the animatable after the surface was reparented (or reparent // wasn't possible, but we still need to invoke the callback) - mAnimatable.onAnimationLeashLost(t); + animatable.onAnimationLeashLost(t); scheduleAnim = true; } - - if (scheduleAnim) { - mService.scheduleAnimationLocked(); - } + return scheduleAnim; } - private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width, - int height, boolean hidden) { + static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface, + Transaction t, int width, int height, int x, int y, boolean hidden) { if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash"); - final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash() - .setParent(mAnimatable.getAnimationLeashParent()) + final SurfaceControl.Builder builder = animatable.makeAnimationLeash() + .setParent(animatable.getAnimationLeashParent()) .setHidden(hidden) .setName(surface + " - animation-leash"); final SurfaceControl leash = builder.build(); t.setWindowCrop(leash, width, height); - - // TODO: rely on builder.setHidden(hidden) instead of show and setAlpha when b/138459974 is - // fixed. + t.setPosition(leash, x, y); t.show(leash); t.setAlpha(leash, hidden ? 0 : 1); @@ -489,7 +507,8 @@ class SurfaceAnimator { void commitPendingTransaction(); /** - * Called when the was created. + * Called when the animation leash is created. Note that this is also called by + * {@link SurfaceFreezer}, so this doesn't mean we're about to start animating. * * @param t The transaction to use to apply any necessary changes. * @param leash The leash that was created. @@ -497,6 +516,14 @@ class SurfaceAnimator { void onAnimationLeashCreated(Transaction t, SurfaceControl leash); /** + * Called when the animator is about to start animating the leash. + * + * @param t The transaction to use to apply any necessary changes. + * @param leash The leash that was created. + */ + default void onLeashAnimationStarting(Transaction t, SurfaceControl leash) { } + + /** * Called when the leash is being destroyed, or when the leash is being transferred to * another SurfaceAnimator. * diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java new file mode 100644 index 000000000000..20435ea7dfaf --- /dev/null +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -0,0 +1,245 @@ +/* + * 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.wm; + +import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.GraphicBuffer; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.view.Surface; +import android.view.SurfaceControl; + +import com.android.server.protolog.common.ProtoLog; + +import java.util.function.Supplier; + +/** + * This class handles "freezing" of an Animatable. The Animatable in question should implement + * Freezable. + * + * The point of this is to enable WindowContainers to each be capable of freezing themselves. + * Freezing means taking a snapshot and placing it above everything in the sub-hierarchy. + * The "placing above" requires that a parent surface be inserted above the target surface so that + * the target surface and the snapshot are siblings. + * + * The overall flow for a transition using this would be: + * 1. Set transition and record animatable in mChangingApps + * 2. Call {@link #freeze} to set-up the leashes and cover with a snapshot. + * 3. When transition participants are ready, start SurfaceAnimator with this as a parameter + * 4. SurfaceAnimator will then {@link #takeLeashForAnimation} instead of creating another leash. + * 5. The animation system should eventually clean this up via {@link #unfreeze}. + */ +class SurfaceFreezer { + + private final Freezable mAnimatable; + private final WindowManagerService mWmService; + private SurfaceControl mLeash; + Snapshot mSnapshot = null; + final Rect mFreezeBounds = new Rect(); + + /** + * @param animatable The object to animate. + */ + SurfaceFreezer(Freezable animatable, WindowManagerService service) { + mAnimatable = animatable; + mWmService = service; + } + + /** + * Freeze the target surface. This is done by creating a leash (inserting a parent surface + * above the target surface) and then taking a snapshot and placing it over the target surface. + * + * @param startBounds The original bounds (on screen) of the surface we are snapshotting. + */ + void freeze(SurfaceControl.Transaction t, Rect startBounds) { + mFreezeBounds.set(startBounds); + + mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(), + t, startBounds.width(), startBounds.height(), startBounds.left, startBounds.top, + false /* hidden */); + mAnimatable.onAnimationLeashCreated(t, mLeash); + + SurfaceControl freezeTarget = mAnimatable.getFreezeSnapshotTarget(); + if (freezeTarget != null) { + GraphicBuffer snapshot = createSnapshotBuffer(freezeTarget, startBounds); + if (snapshot != null) { + mSnapshot = new Snapshot(mWmService.mSurfaceFactory, t, snapshot, mLeash); + } + } + } + + /** + * Used by {@link SurfaceAnimator}. This "transfers" the leash to be used for animation. + * By transferring the leash, this will no longer try to clean-up the leash when finished. + */ + SurfaceControl takeLeashForAnimation() { + SurfaceControl out = mLeash; + mLeash = null; + return out; + } + + /** + * Clean-up the snapshot and remove leash. If the leash was taken, this just cleans-up the + * snapshot. + */ + void unfreeze(SurfaceControl.Transaction t) { + if (mSnapshot != null) { + mSnapshot.destroy(t); + } + if (mLeash == null) { + return; + } + SurfaceControl leash = mLeash; + mLeash = null; + final boolean scheduleAnim = SurfaceAnimator.removeLeash(t, mAnimatable, leash, + false /* destroy */); + if (scheduleAnim) { + mWmService.scheduleAnimationLocked(); + } + } + + boolean hasLeash() { + return mLeash != null; + } + + private static GraphicBuffer createSnapshotBuffer(@NonNull SurfaceControl target, + @Nullable Rect bounds) { + Rect cropBounds = null; + if (bounds != null) { + cropBounds = new Rect(bounds); + cropBounds.offsetTo(0, 0); + } + final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer = + SurfaceControl.captureLayers( + target, cropBounds, 1.f /* frameScale */, PixelFormat.RGBA_8888); + final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer() + : null; + if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { + return null; + } + return buffer; + } + + class Snapshot { + private SurfaceControl mSurfaceControl; + private AnimationAdapter mAnimation; + private SurfaceAnimator.OnAnimationFinishedCallback mFinishedCallback; + + /** + * @param t Transaction to create the thumbnail in. + * @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with. + */ + Snapshot(Supplier<Surface> surfaceFactory, SurfaceControl.Transaction t, + GraphicBuffer thumbnailHeader, SurfaceControl parent) { + Surface drawSurface = surfaceFactory.get(); + // We can't use a delegating constructor since we need to + // reference this::onAnimationFinished + final int width = thumbnailHeader.getWidth(); + final int height = thumbnailHeader.getHeight(); + + mSurfaceControl = mAnimatable.makeAnimationLeash() + .setName("snapshot anim: " + mAnimatable.toString()) + .setBufferSize(width, height) + .setFormat(PixelFormat.TRANSLUCENT) + .setParent(parent) + .build(); + + ProtoLog.i(WM_SHOW_TRANSACTIONS, " THUMBNAIL %s: CREATE", mSurfaceControl); + + // Transfer the thumbnail to the surface + drawSurface.copyFrom(mSurfaceControl); + drawSurface.attachAndQueueBuffer(thumbnailHeader); + drawSurface.release(); + t.show(mSurfaceControl); + + // We parent the thumbnail to the container, and just place it on top of anything else + // in the container. + t.setLayer(mSurfaceControl, Integer.MAX_VALUE); + } + + void destroy(SurfaceControl.Transaction t) { + if (mSurfaceControl == null) { + return; + } + t.remove(mSurfaceControl); + mSurfaceControl = null; + } + + /** + * Starts an animation. + * + * @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the + * component responsible for running the animation. It runs the animation with + * {@link AnimationAdapter#startAnimation} once the hierarchy with + * the Leash has been set up. + * @param animationFinishedCallback The callback being triggered when the animation + * finishes. + */ + void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type, + @Nullable SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback) { + cancelAnimation(t, true /* restarting */); + mAnimation = anim; + mFinishedCallback = animationFinishedCallback; + if (mSurfaceControl == null) { + cancelAnimation(t, false /* restarting */); + return; + } + mAnimation.startAnimation(mSurfaceControl, t, type, animationFinishedCallback); + } + + /** + * Cancels the animation, and resets the leash. + * + * @param t The transaction to use for all cancelling surface operations. + * @param restarting Whether we are restarting the animation. + */ + private void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) { + final SurfaceControl leash = mSurfaceControl; + final AnimationAdapter animation = mAnimation; + final SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback = + mFinishedCallback; + mAnimation = null; + mFinishedCallback = null; + if (animation != null) { + animation.onAnimationCancelled(leash); + if (!restarting) { + if (animationFinishedCallback != null) { + animationFinishedCallback.onAnimationFinished( + ANIMATION_TYPE_APP_TRANSITION, animation); + } + } + } + if (!restarting) { + // TODO: do we need to destroy? + destroy(t); + } + } + } + + /** freezable */ + public interface Freezable extends SurfaceAnimator.Animatable { + /** + * @return The surface to take a snapshot of. If this returns {@code null}, no snapshot + * will be generated (but the rest of the freezing logic will still happen). + */ + @Nullable SurfaceControl getFreezeSnapshotTarget(); + } +} diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 76805e9f6342..27acb2356585 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -58,6 +58,7 @@ import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.SurfaceControl.METADATA_TASK_ID; +import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; @@ -78,6 +79,9 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; +import static com.android.server.wm.IdentifierProto.HASH_CODE; +import static com.android.server.wm.IdentifierProto.TITLE; +import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -119,10 +123,13 @@ import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; +import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.ITaskOrganizer; +import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.Surface; import android.view.SurfaceControl; @@ -1884,6 +1891,8 @@ class Task extends WindowContainer<WindowContainer> { .setBounds(mLastNonFullscreenBounds); } + final int prevWinMode = getWindowingMode(); + mTmpPrevBounds.set(getBounds()); final boolean wasInMultiWindowMode = inMultiWindowMode(); super.onConfigurationChanged(newParentConfig); if (wasInMultiWindowMode != inMultiWindowMode()) { @@ -1891,6 +1900,12 @@ class Task extends WindowContainer<WindowContainer> { updateShadowsRadius(isFocused(), getPendingTransaction()); } + final int newWinMode = getWindowingMode(); + if ((prevWinMode != newWinMode) && (mDisplayContent != null) + && shouldStartChangeTransition(prevWinMode, newWinMode)) { + initializeChangeTransition(mTmpPrevBounds); + } + // If the configuration supports persistent bounds (eg. Freeform), keep track of the // current (non-fullscreen) bounds for persistence. if (getWindowConfiguration().persistTaskBounds()) { @@ -1905,6 +1920,63 @@ class Task extends WindowContainer<WindowContainer> { } /** + * Initializes a change transition. See {@link SurfaceFreezer} for more information. + */ + private void initializeChangeTransition(Rect startBounds) { + mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE, + false /* alwaysKeepCurrent */, 0, false /* forceOverride */); + mDisplayContent.mChangingContainers.add(this); + + mSurfaceFreezer.freeze(getPendingTransaction(), startBounds); + } + + private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) { + if (mWmService.mDisableTransitionAnimation + || !isVisible() + || getDisplayContent().mAppTransition.isTransitionSet() + || getSurfaceControl() == null) { + return false; + } + // Only do an animation into and out-of freeform mode for now. Other mode + // transition animations are currently handled by system-ui. + return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM); + } + + @VisibleForTesting + boolean isInChangeTransition() { + return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransit(mTransit); + } + + @Override + public SurfaceControl getFreezeSnapshotTarget() { + final int transit = mDisplayContent.mAppTransition.getAppTransition(); + if (!AppTransition.isChangeTransit(transit)) { + return null; + } + // Skip creating snapshot if this transition is controlled by a remote animator which + // doesn't need it. + final ArraySet<Integer> activityTypes = new ArraySet<>(); + activityTypes.add(getActivityType()); + final RemoteAnimationAdapter adapter = + mDisplayContent.mAppTransitionController.getRemoteAnimationOverride( + this, transit, activityTypes); + if (adapter != null && !adapter.getChangeNeedsSnapshot()) { + return null; + } + return getSurfaceControl(); + } + + @Override + void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(HASH_CODE, System.identityHashCode(this)); + proto.write(USER_ID, mUserId); + proto.write(TITLE, intent != null && intent.getComponent() != null + ? intent.getComponent().flattenToShortString() : "Task"); + proto.end(token); + } + + /** * Saves launching state if necessary so that we can launch the activity to its latest state. * It only saves state if this task has been shown to user and it's in fullscreen or freeform * mode on freeform displays. @@ -2036,18 +2108,6 @@ class Task extends WindowContainer<WindowContainer> { intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets); } - /** - * Asks docked-divider controller for the smallestwidthdp given bounds. - * @param bounds bounds to calculate smallestwidthdp for. - */ - private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) { - DisplayContent dc = getDisplayContent(); - if (dc != null) { - return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds); - } - return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; - } - void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Configuration parentConfig) { computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */); @@ -2614,12 +2674,22 @@ class Task extends WindowContainer<WindowContainer> { if (!isRootTask) { adjustBoundsForDisplayChangeIfNeeded(dc); } + final DisplayContent prevDc = mDisplayContent; super.onDisplayChanged(dc); if (!isRootTask) { final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY; mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged( mTaskId, displayId); } + if (prevDc != null && prevDc.mChangingContainers.remove(this)) { + // This gets called *after* this has been reparented to the new display. + // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN), + // so this token is now "frozen" while waiting for the animation to start on prevDc + // (which will be cancelled since the window is no-longer a child). However, since this + // is no longer a child of prevDc, this won't be notified of the cancelled animation, + // so we need to cancel the change transition here. + mSurfaceFreezer.unfreeze(getPendingTransaction()); + } } /** @@ -3010,15 +3080,6 @@ class Task extends WindowContainer<WindowContainer> { return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); }); } - /** - * @return {@code true} if changing app transition is running. - */ - @Override - boolean isChangingAppTransition() { - final ActivityRecord activity = getTopVisibleActivity(); - return activity != null && getDisplayContent().mChangingApps.contains(activity); - } - @Override RemoteAnimationTarget createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 5c73f92ee6cd..f83b0522846c 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -18,19 +18,18 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; -import static com.android.server.wm.TaskSnapshotPersister.DISABLE_HIGH_RES_BITMAPS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.RecordingCanvas; import android.graphics.Rect; import android.graphics.RenderNode; @@ -89,14 +88,6 @@ class TaskSnapshotController { @VisibleForTesting static final int SNAPSHOT_MODE_NONE = 2; - /** - * Constant for <code>scaleFactor</code> when calling {@link #snapshotTask} which is - * interpreted as using the most appropriate scale ratio for the system. - * This may yield a smaller ratio on low memory devices. - */ - @VisibleForTesting - static final float SNAPSHOT_SCALE_AUTO = -1f; - private final WindowManagerService mService; private final TaskSnapshotCache mCache; @@ -229,7 +220,7 @@ class TaskSnapshotController { @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk, boolean isLowResolution) { return mCache.getSnapshot(taskId, userId, restoreFromDisk, isLowResolution - || DISABLE_HIGH_RES_BITMAPS); + && mPersister.enableLowResSnapshots()); } /** @@ -273,8 +264,6 @@ class TaskSnapshotController { * information from the task and populates the builder. * * @param task the task to capture - * @param scaleFraction the scale fraction between 0-1.0, or {@link #SNAPSHOT_SCALE_AUTO} - * to automatically select * @param pixelFormat the desired pixel format, or {@link PixelFormat#UNKNOWN} to * automatically select * @param builder the snapshot builder to populate @@ -282,8 +271,7 @@ class TaskSnapshotController { * @return true if the state of the task is ok to proceed */ @VisibleForTesting - boolean prepareTaskSnapshot(Task task, float scaleFraction, int pixelFormat, - TaskSnapshot.Builder builder) { + boolean prepareTaskSnapshot(Task task, int pixelFormat, TaskSnapshot.Builder builder) { if (!mService.mPolicy.isScreenOn()) { if (DEBUG_SCREENSHOT) { Slog.i(TAG_WM, "Attempted to take screenshot while display was off."); @@ -314,18 +302,6 @@ class TaskSnapshotController { builder.setId(System.currentTimeMillis()); builder.setContentInsets(getInsets(mainWindow)); - final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic(); - - if (scaleFraction == SNAPSHOT_SCALE_AUTO) { - builder.setScaleFraction(isLowRamDevice - ? mPersister.getLowResScale() - : mHighResTaskSnapshotScale); - builder.setIsLowResolution(isLowRamDevice); - } else { - builder.setScaleFraction(scaleFraction); - builder.setIsLowResolution(scaleFraction < 1.0f); - } - final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE; final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0; @@ -351,13 +327,23 @@ class TaskSnapshotController { @Nullable SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task, + TaskSnapshot.Builder builder) { + Point taskSize = new Point(); + final SurfaceControl.ScreenshotGraphicBuffer taskSnapshot = createTaskSnapshot(task, + mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize); + builder.setTaskSize(taskSize); + return taskSnapshot; + } + + @Nullable + SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task, float scaleFraction) { - return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888); + return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888, null); } @Nullable SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task, - float scaleFraction, int pixelFormat) { + float scaleFraction, int pixelFormat, Point outTaskSize) { if (task.getSurfaceControl() == null) { if (DEBUG_SCREENSHOT) { Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task); @@ -369,6 +355,10 @@ class TaskSnapshotController { final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer = SurfaceControl.captureLayers( task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat); + if (outTaskSize != null) { + outTaskSize.x = mTmpRect.width(); + outTaskSize.y = mTmpRect.height(); + } final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer() : null; if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { @@ -379,21 +369,20 @@ class TaskSnapshotController { @Nullable TaskSnapshot snapshotTask(Task task) { - return snapshotTask(task, SNAPSHOT_SCALE_AUTO, PixelFormat.UNKNOWN); + return snapshotTask(task, PixelFormat.UNKNOWN); } @Nullable - TaskSnapshot snapshotTask(Task task, float scaleFraction, int pixelFormat) { + TaskSnapshot snapshotTask(Task task, int pixelFormat) { TaskSnapshot.Builder builder = new TaskSnapshot.Builder(); - if (!prepareTaskSnapshot(task, scaleFraction, pixelFormat, builder)) { + if (!prepareTaskSnapshot(task, pixelFormat, builder)) { // Failed some pre-req. Has been logged. return null; } final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer = - createTaskSnapshot(task, builder.getScaleFraction(), - builder.getPixelFormat()); + createTaskSnapshot(task, builder); if (screenshotBuffer == null) { // Failed to acquire image. Has been logged. @@ -472,8 +461,10 @@ class TaskSnapshotController { final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags, attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription(), mHighResTaskSnapshotScale, mainWindow.getRequestedInsetsState()); - final int width = (int) (task.getBounds().width() * mHighResTaskSnapshotScale); - final int height = (int) (task.getBounds().height() * mHighResTaskSnapshotScale); + final int taskWidth = task.getBounds().width(); + final int taskHeight = task.getBounds().height(); + final int width = (int) (taskWidth * mHighResTaskSnapshotScale); + final int height = (int) (taskHeight * mHighResTaskSnapshotScale); final RenderNode node = RenderNode.create("TaskSnapshotController", null); node.setLeftTopRightBottom(0, 0, width, height); @@ -494,9 +485,9 @@ class TaskSnapshotController { System.currentTimeMillis() /* id */, topChild.mActivityComponent, hwBitmap.createGraphicBufferHandle(), hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation, - mainWindow.getWindowConfiguration().getRotation(), - getInsets(mainWindow), ActivityManager.isLowRamDeviceStatic() /* isLowResolution */, - mHighResTaskSnapshotScale, false /* isRealSnapshot */, task.getWindowingMode(), + mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight), + getInsets(mainWindow), false /* isLowResolution */, + false /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task), false); } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java index 01f3427d78e1..c20ce5f40bc2 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.content.ComponentName; import android.graphics.Bitmap; @@ -26,6 +27,7 @@ import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.graphics.GraphicBuffer; +import android.graphics.Point; import android.graphics.Rect; import android.util.Slog; @@ -52,28 +54,110 @@ class TaskSnapshotLoader { mPersister = persister; } + static class PreRLegacySnapshotConfig { + /** + * If isPreRLegacy is {@code true}, specifies the scale the snapshot was taken at + */ + final float mScale; + + /** + * If {@code true}, always load *_reduced.jpg file, no matter what was requested + */ + final boolean mForceLoadReducedJpeg; + + PreRLegacySnapshotConfig(float scale, boolean forceLoadReducedJpeg) { + mScale = scale; + mForceLoadReducedJpeg = forceLoadReducedJpeg; + } + } + + /** + * When device is upgraded, we might be loading a legacy snapshot. In those cases, + * restore the scale based on how it was configured historically. See history of + * TaskSnapshotPersister for more information. + * + * | low_ram=false | low_ram=true + * +------------------------------------------------------------------------------+ + * O | *.jpg = 100%, *_reduced.jpg = 50% | + * | +-----------------------------------------| + * P | | *.jpg = NONE, *_reduced.jpg = 60% | + * +------------------------------------+-----------------------------------------+ + * Q | *.jpg = proto.scale, | *.jpg = NONE, | + * | *_reduced.jpg = 50% * proto.scale | *_reduced.jpg = proto.scale | + * +------------------------------------+-----------------------------------------+ + * + * @return null if Android R, otherwise a PreRLegacySnapshotConfig object + */ + PreRLegacySnapshotConfig getLegacySnapshotConfig(int taskWidth, float legacyScale, + boolean highResFileExists, boolean loadLowResolutionBitmap) { + float preRLegacyScale = 0; + boolean forceLoadReducedJpeg = false; + boolean isPreRLegacySnapshot = (taskWidth == 0); + if (!isPreRLegacySnapshot) { + return null; + } + final boolean isPreQLegacyProto = isPreRLegacySnapshot + && (Float.compare(legacyScale, 0f) == 0); + + if (isPreQLegacyProto) { + // Android O or Android P + if (ActivityManager.isLowRamDeviceStatic() && !highResFileExists) { + // Android P w/ low_ram=true + preRLegacyScale = 0.6f; + // Force bitmapFile to always be *_reduced.jpg + forceLoadReducedJpeg = true; + } else { + // Android O, OR Android P w/ low_ram=false + preRLegacyScale = loadLowResolutionBitmap ? 0.5f : 1.0f; + } + } else if (isPreRLegacySnapshot) { + // If not pre-Q but is pre-R, then it must be Android Q + if (ActivityManager.isLowRamDeviceStatic()) { + preRLegacyScale = legacyScale; + // Force bitmapFile to always be *_reduced.jpg + forceLoadReducedJpeg = true; + } else { + preRLegacyScale = + loadLowResolutionBitmap ? 0.5f * legacyScale : legacyScale; + } + } + return new PreRLegacySnapshotConfig(preRLegacyScale, forceLoadReducedJpeg); + } + /** * Loads a task from the disk. * <p> * Do not hold the window manager lock when calling this method, as we directly read data from * disk here, which might be slow. * - * @param taskId The id of the task to load. - * @param userId The id of the user the task belonged to. - * @param isLowResolution Whether to load a reduced resolution version of the snapshot. + * @param taskId The id of the task to load. + * @param userId The id of the user the task belonged to. + * @param loadLowResolutionBitmap Whether to load a low resolution resolution version of the + * snapshot. * @return The loaded {@link TaskSnapshot} or {@code null} if it couldn't be loaded. */ - TaskSnapshot loadTask(int taskId, int userId, boolean isLowResolution) { + TaskSnapshot loadTask(int taskId, int userId, boolean loadLowResolutionBitmap) { final File protoFile = mPersister.getProtoFile(taskId, userId); - final File bitmapFile = isLowResolution - ? mPersister.getLowResolutionBitmapFile(taskId, userId) - : mPersister.getHighResolutionBitmapFile(taskId, userId); - if (bitmapFile == null || !protoFile.exists() || !bitmapFile.exists()) { + if (!protoFile.exists()) { return null; } try { final byte[] bytes = Files.readAllBytes(protoFile.toPath()); final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes); + final File highResBitmap = mPersister.getHighResolutionBitmapFile(taskId, userId); + + PreRLegacySnapshotConfig legacyConfig = getLegacySnapshotConfig(proto.taskWidth, + proto.legacyScale, highResBitmap.exists(), loadLowResolutionBitmap); + + boolean forceLoadReducedJpeg = + legacyConfig != null && legacyConfig.mForceLoadReducedJpeg; + File bitmapFile = (loadLowResolutionBitmap || forceLoadReducedJpeg) + ? mPersister.getLowResolutionBitmapFile(taskId, userId) : highResBitmap; + + if (!bitmapFile.exists()) { + return null; + } + final Options options = new Options(); options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent ? Config.RGB_565 @@ -99,13 +183,20 @@ class TaskSnapshotLoader { final ComponentName topActivityComponent = ComponentName.unflattenFromString( proto.topActivityComponent); - // For legacy snapshots, restore the scale based on the reduced resolution state - final float legacyScale = isLowResolution ? mPersister.getLowResScale() : 1f; - final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale; - return new TaskSnapshot(proto.id, topActivityComponent, buffer, hwBitmap.getColorSpace(), - proto.orientation, proto.rotation, + + Point taskSize; + if (legacyConfig != null) { + int taskWidth = (int) ((float) hwBitmap.getWidth() / legacyConfig.mScale); + int taskHeight = (int) ((float) hwBitmap.getHeight() / legacyConfig.mScale); + taskSize = new Point(taskWidth, taskHeight); + } else { + taskSize = new Point(proto.taskWidth, proto.taskHeight); + } + + return new TaskSnapshot(proto.id, topActivityComponent, buffer, + hwBitmap.getColorSpace(), proto.orientation, proto.rotation, taskSize, new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom), - isLowResolution, scale, proto.isRealSnapshot, proto.windowingMode, + loadLowResolutionBitmap, proto.isRealSnapshot, proto.windowingMode, proto.systemUiVisibility, proto.isTranslucent); } catch (IOException e) { Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index 31212b8a6bd9..164d3e055e94 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -21,8 +21,8 @@ import static android.graphics.Bitmap.CompressFormat.JPEG; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.NonNull; import android.annotation.TestApi; -import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; @@ -52,8 +52,6 @@ class TaskSnapshotPersister { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM; private static final String SNAPSHOTS_DIRNAME = "snapshots"; private static final String LOW_RES_FILE_POSTFIX = "_reduced"; - private static final float LOW_RAM_REDUCED_SCALE = .8f; - static final boolean DISABLE_HIGH_RES_BITMAPS = ActivityManager.isLowRamDeviceStatic(); private static final long DELAY_MS = 100; private static final int QUALITY = 95; private static final String PROTO_EXTENSION = ".proto"; @@ -71,7 +69,8 @@ class TaskSnapshotPersister { private boolean mStarted; private final Object mLock = new Object(); private final DirectoryResolver mDirectoryResolver; - private final float mLowResScale; + private final float mLowResScaleFactor; + private boolean mEnableLowResSnapshots; private final boolean mUse16BitFormat; /** @@ -83,13 +82,29 @@ class TaskSnapshotPersister { TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) { mDirectoryResolver = resolver; + final float highResTaskSnapshotScale = service.mContext.getResources().getFloat( + com.android.internal.R.dimen.config_highResTaskSnapshotScale); + final float lowResTaskSnapshotScale = service.mContext.getResources().getFloat( + com.android.internal.R.dimen.config_lowResTaskSnapshotScale); - if (ActivityManager.isLowRamDeviceStatic()) { - mLowResScale = LOW_RAM_REDUCED_SCALE; + if (lowResTaskSnapshotScale < 0 || 1 <= lowResTaskSnapshotScale) { + throw new RuntimeException("Low-res scale must be between 0 and 1"); + } + if (highResTaskSnapshotScale <= 0 || 1 < highResTaskSnapshotScale) { + throw new RuntimeException("High-res scale must be between 0 and 1"); + } + if (highResTaskSnapshotScale <= lowResTaskSnapshotScale) { + throw new RuntimeException("High-res scale must be greater than low-res scale"); + } + + if (lowResTaskSnapshotScale > 0) { + mLowResScaleFactor = lowResTaskSnapshotScale / highResTaskSnapshotScale; + setEnableLowResSnapshots(true); } else { - mLowResScale = service.mContext.getResources().getFloat( - com.android.internal.R.dimen.config_lowResTaskSnapshotScale); + mLowResScaleFactor = 0; + setEnableLowResSnapshots(false); } + mUse16BitFormat = service.mContext.getResources().getBoolean( com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat); } @@ -155,13 +170,16 @@ class TaskSnapshotPersister { } } + boolean enableLowResSnapshots() { + return mEnableLowResSnapshots; + } + /** - * Gets the scaling the persister uses for low resolution task snapshots. - * - * @return the lowResBitmap scale of task snapshots when they are set to be low res + * Not to be used. Only here for testing. */ - float getLowResScale() { - return mLowResScale; + @VisibleForTesting + void setEnableLowResSnapshots(boolean enabled) { + mEnableLowResSnapshots = enabled; } /** @@ -213,14 +231,10 @@ class TaskSnapshotPersister { } File getHighResolutionBitmapFile(int taskId, int userId) { - // Full sized bitmaps are disabled on low ram devices - if (DISABLE_HIGH_RES_BITMAPS) { - Slog.wtf(TAG, "This device does not support full sized resolution bitmaps."); - return null; - } return new File(getDirectory(userId), taskId + BITMAP_EXTENSION); } + @NonNull File getLowResolutionBitmapFile(int taskId, int userId) { return new File(getDirectory(userId), taskId + LOW_RES_FILE_POSTFIX + BITMAP_EXTENSION); } @@ -234,11 +248,11 @@ class TaskSnapshotPersister { final File protoFile = getProtoFile(taskId, userId); final File bitmapLowResFile = getLowResolutionBitmapFile(taskId, userId); protoFile.delete(); - bitmapLowResFile.delete(); - - // Low ram devices do not have a full sized file to delete - if (!DISABLE_HIGH_RES_BITMAPS) { - final File bitmapFile = getHighResolutionBitmapFile(taskId, userId); + if (bitmapLowResFile.exists()) { + bitmapLowResFile.delete(); + } + final File bitmapFile = getHighResolutionBitmapFile(taskId, userId); + if (bitmapFile.exists()) { bitmapFile.delete(); } } @@ -343,6 +357,8 @@ class TaskSnapshotPersister { final TaskSnapshotProto proto = new TaskSnapshotProto(); proto.orientation = mSnapshot.getOrientation(); proto.rotation = mSnapshot.getRotation(); + proto.taskWidth = mSnapshot.getTaskSize().x; + proto.taskHeight = mSnapshot.getTaskSize().y; proto.insetLeft = mSnapshot.getContentInsets().left; proto.insetTop = mSnapshot.getContentInsets().top; proto.insetRight = mSnapshot.getContentInsets().right; @@ -352,7 +368,6 @@ class TaskSnapshotPersister { proto.systemUiVisibility = mSnapshot.getSystemUiVisibility(); proto.isTranslucent = mSnapshot.isTranslucent(); proto.topActivityComponent = mSnapshot.getTopActivityComponent().flattenToString(); - proto.scale = mSnapshot.getScale(); proto.id = mSnapshot.getId(); final byte[] bytes = TaskSnapshotProto.toByteArray(proto); final File file = getProtoFile(mTaskId, mUserId); @@ -379,39 +394,38 @@ class TaskSnapshotPersister { } final Bitmap swBitmap = bitmap.copy(Config.ARGB_8888, false /* isMutable */); - final Bitmap lowResBitmap = mSnapshot.isLowResolution() - ? swBitmap - : Bitmap.createScaledBitmap(swBitmap, - (int) (bitmap.getWidth() * mLowResScale), - (int) (bitmap.getHeight() * mLowResScale), true /* filter */); - final File lowResFile = getLowResolutionBitmapFile(mTaskId, mUserId); + final File file = getHighResolutionBitmapFile(mTaskId, mUserId); try { - FileOutputStream lowResFos = new FileOutputStream(lowResFile); - lowResBitmap.compress(JPEG, QUALITY, lowResFos); - lowResFos.close(); + FileOutputStream fos = new FileOutputStream(file); + swBitmap.compress(JPEG, QUALITY, fos); + fos.close(); } catch (IOException e) { - Slog.e(TAG, "Unable to open " + lowResFile + " for persisting.", e); + Slog.e(TAG, "Unable to open " + file + " for persisting.", e); return false; } - lowResBitmap.recycle(); - // For snapshots with lowResBitmap resolution, do not create or save full sized bitmaps - if (mSnapshot.isLowResolution()) { + if (!enableLowResSnapshots()) { swBitmap.recycle(); return true; } - final File file = getHighResolutionBitmapFile(mTaskId, mUserId); + final Bitmap lowResBitmap = Bitmap.createScaledBitmap(swBitmap, + (int) (bitmap.getWidth() * mLowResScaleFactor), + (int) (bitmap.getHeight() * mLowResScaleFactor), true /* filter */); + swBitmap.recycle(); + + final File lowResFile = getLowResolutionBitmapFile(mTaskId, mUserId); try { - FileOutputStream fos = new FileOutputStream(file); - swBitmap.compress(JPEG, QUALITY, fos); - fos.close(); + FileOutputStream lowResFos = new FileOutputStream(lowResFile); + lowResBitmap.compress(JPEG, QUALITY, lowResFos); + lowResFos.close(); } catch (IOException e) { - Slog.e(TAG, "Unable to open " + file + " for persisting.", e); + Slog.e(TAG, "Unable to open " + lowResFile + " for persisting.", e); return false; } - swBitmap.recycle(); + lowResBitmap.recycle(); + return true; } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index f4e42455087d..eb005e0f7eda 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; + import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getColorViewLeftInset; @@ -53,9 +54,11 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.GraphicBuffer; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.RectF; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -131,6 +134,8 @@ class TaskSnapshotSurface implements StartingSurface { private final Rect mContentInsets = new Rect(); private final Rect mFrame = new Rect(); private TaskSnapshot mSnapshot; + private final RectF mTmpSnapshotSize = new RectF(); + private final RectF mTmpDstFrame = new RectF(); private final CharSequence mTitle; private boolean mHasDrawn; private long mShownTime; @@ -141,6 +146,8 @@ class TaskSnapshotSurface implements StartingSurface { @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter; private final int mOrientationOnCreation; private final SurfaceControl.Transaction mTransaction; + private final Matrix mSnapshotMatrix = new Matrix(); + private final float[] mTmpFloat9 = new float[9]; static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity, TaskSnapshot snapshot) { @@ -365,13 +372,17 @@ class TaskSnapshotSurface implements StartingSurface { frame = calculateSnapshotFrame(crop); mTransaction.setWindowCrop(mChildSurfaceControl, crop); mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top); + mTmpDstFrame.set(frame); } else { frame = null; + mTmpDstFrame.set(mFrame); } // Scale the mismatch dimensions to fill the task bounds - final float scale = 1 / mSnapshot.getScale(); - mTransaction.setMatrix(mChildSurfaceControl, scale, 0, 0, scale); + mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight()); + mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL); + mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9); + mTransaction.apply(); surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace()); surface.release(); @@ -395,13 +406,17 @@ class TaskSnapshotSurface implements StartingSurface { rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight()); final Rect insets = mSnapshot.getContentInsets(); + final float scaleX = (float) mSnapshot.getSnapshot().getWidth() / mSnapshot.getTaskSize().x; + final float scaleY = + (float) mSnapshot.getSnapshot().getHeight() / mSnapshot.getTaskSize().y; + // Let's remove all system decorations except the status bar, but only if the task is at the // very top of the screen. final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0; - rect.inset((int) (insets.left * mSnapshot.getScale()), - isTop ? 0 : (int) (insets.top * mSnapshot.getScale()), - (int) (insets.right * mSnapshot.getScale()), - (int) (insets.bottom * mSnapshot.getScale())); + rect.inset((int) (insets.left * scaleX), + isTop ? 0 : (int) (insets.top * scaleY), + (int) (insets.right * scaleX), + (int) (insets.bottom * scaleY)); return rect; } @@ -412,14 +427,20 @@ class TaskSnapshotSurface implements StartingSurface { */ @VisibleForTesting Rect calculateSnapshotFrame(Rect crop) { - final Rect frame = new Rect(crop); - final float scale = mSnapshot.getScale(); + final float scaleX = (float) mSnapshot.getSnapshot().getWidth() / mSnapshot.getTaskSize().x; + final float scaleY = + (float) mSnapshot.getSnapshot().getHeight() / mSnapshot.getTaskSize().y; // Rescale the frame from snapshot to window coordinate space - frame.scale(1 / scale); + final Rect frame = new Rect( + (int) (crop.left / scaleX + 0.5f), + (int) (crop.top / scaleY + 0.5f), + (int) (crop.right / scaleX + 0.5f), + (int) (crop.bottom / scaleY + 0.5f) + ); // By default, offset it to to top/left corner - frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale)); + frame.offsetTo((int) (-crop.left / scaleX), (int) (-crop.top / scaleY)); // However, we also need to make space for the navigation bar on the left side. final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left, diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 137d122cd6d5..669eb7804d41 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -669,8 +669,7 @@ class WallpaperController { * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of * the opening apps should be a wallpaper target. */ - void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps, - ArraySet<ActivityRecord> changingApps) { + void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps) { boolean adjust = false; if ((mDisplayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) { adjust = true; @@ -682,15 +681,6 @@ class WallpaperController { break; } } - if (!adjust) { - for (int i = changingApps.size() - 1; i >= 0; --i) { - final ActivityRecord activity = changingApps.valueAt(i); - if (activity.windowsCanBeWallpaperTarget()) { - adjust = true; - break; - } - } - } } if (adjust) { diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index fd91bc549f07..b6be386fa181 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -50,7 +50,6 @@ public class WindowAnimator { final WindowManagerPolicy mPolicy; /** Is any window animating? */ - private boolean mAnimating; private boolean mLastRootAnimating; final Choreographer.FrameCallback mAnimationFrameCallback; @@ -135,7 +134,6 @@ public class WindowAnimator { synchronized (mService.mGlobalLock) { mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS; mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE; - mAnimating = false; if (DEBUG_WINDOW_TRACE) { Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime); } @@ -160,17 +158,12 @@ public class WindowAnimator { final DisplayContent dc = mService.mRoot.getDisplayContent(displayId); dc.checkAppWindowsReadyToShow(); - orAnimating(dc.getDockedDividerController().animate(mCurrentTime)); if (accessibilityController != null) { accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId, mTransaction); } } - if (!mAnimating) { - cancelAnimation(); - } - if (mService.mWatermark != null) { mService.mWatermark.drawIfNeeded(); } @@ -220,7 +213,7 @@ public class WindowAnimator { executeAfterPrepareSurfacesRunnables(); if (DEBUG_WINDOW_TRACE) { - Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating + Slog.i(TAG, "!!! animate: exit" + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams) + " hasPendingLayoutChanges=" + hasPendingLayoutChanges); } @@ -302,10 +295,6 @@ public class WindowAnimator { private class DisplayContentsAnimator { } - boolean isAnimating() { - return mAnimating; - } - boolean isAnimationScheduled() { return mAnimationFrameCallbackScheduled; } @@ -314,14 +303,6 @@ public class WindowAnimator { return mChoreographer; } - void setAnimating(boolean animating) { - mAnimating = animating; - } - - void orAnimating(boolean animating) { - mAnimating |= animating; - } - /** * Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and * the corresponding transaction is closed and applied. diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 7a4d0b0d9169..b12c6980ccce 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -25,9 +25,14 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static android.os.UserHandle.USER_NULL; import static android.view.SurfaceControl.Transaction; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION; +import static com.android.server.wm.IdentifierProto.HASH_CODE; +import static com.android.server.wm.IdentifierProto.TITLE; +import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; @@ -64,6 +69,7 @@ import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.IWindowContainer; import android.view.MagnificationSpec; +import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Builder; @@ -94,7 +100,7 @@ import java.util.function.Predicate; * changes are made to this class. */ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E> - implements Comparable<WindowContainer>, Animatable, + implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable, BLASTSyncEngine.TransactionReadyListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM; @@ -169,6 +175,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * Applied as part of the animation pass in "prepareSurfaces". */ protected final SurfaceAnimator mSurfaceAnimator; + final SurfaceFreezer mSurfaceFreezer; protected final WindowManagerService mWmService; private final Point mTmpPos = new Point(); @@ -252,7 +259,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * where it represents the starting-state snapshot. */ WindowContainerThumbnail mThumbnail; - final Rect mTransitStartRect = new Rect(); final Point mTmpPoint = new Point(); protected final Rect mTmpRect = new Rect(); final Rect mTmpPrevBounds = new Rect(); @@ -277,6 +283,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< mWmService = wms; mPendingTransaction = wms.mTransactionFactory.get(); mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms); + mSurfaceFreezer = new SurfaceFreezer(this, wms); } @Override @@ -524,13 +531,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (mSurfaceControl != null) { getPendingTransaction().remove(mSurfaceControl); - - // Merge to parent transaction to ensure the transactions on this WindowContainer are - // applied in native even if WindowContainer is removed. - if (mParent != null) { - mParent.getPendingTransaction().merge(getPendingTransaction()); - } - setSurfaceControl(null); mLastSurfacePosition.set(0, 0); scheduleAnimation(); @@ -841,7 +841,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @return {@code true} if the container is in changing app transition. */ boolean isChangingAppTransition() { - return false; + return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this); } void sendAppVisibilityToClients() { @@ -893,6 +893,31 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** + * Called when the visibility of a child is asked to change. This is before visibility actually + * changes (eg. a transition animation might play out first). + */ + void onChildVisibilityRequested(boolean visible) { + // If we are changing visibility, then a snapshot isn't necessary and we are no-longer + // part of a change transition. + mSurfaceFreezer.unfreeze(getPendingTransaction()); + if (mDisplayContent != null) { + mDisplayContent.mChangingContainers.remove(this); + } + WindowContainer parent = getParent(); + if (parent != null) { + parent.onChildVisibilityRequested(visible); + } + } + + void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(HASH_CODE, System.identityHashCode(this)); + proto.write(USER_ID, USER_NULL); + proto.write(TITLE, "WindowContainer"); + proto.end(token); + } + + /** * Returns {@code true} if this container is focusable. Generally, if a parent is not focusable, * this will not be focusable either. */ @@ -1924,7 +1949,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // TODO: This should use isVisible() but because isVisible has a really weird meaning at // the moment this doesn't work for all animatable window containers. - mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback); + mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback, + mSurfaceFreezer); } void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden, @@ -1941,6 +1967,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } @Override + public SurfaceControl getFreezeSnapshotTarget() { + return null; + } + + @Override public Builder makeAnimationLeash() { return makeSurface().setContainerLayer(); } @@ -2009,8 +2040,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } if (thumbnailAdapter != null) { - mThumbnail.startAnimation( - getPendingTransaction(), thumbnailAdapter, !isVisible()); + mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(), + thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, + (type, anim) -> { }); } } } else { @@ -2056,7 +2088,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) { final RemoteAnimationController.RemoteAnimationRecord adapters = controller.createRemoteAnimationRecord(this, mTmpPoint, mTmpRect, - (isChanging ? mTransitStartRect : null)); + (isChanging ? mSurfaceFreezer.mFreezeBounds : null)); resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter); } else if (isChanging) { final float durationScale = mWmService.getTransitionAnimationScaleLocked(); @@ -2064,14 +2096,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y); final AnimationAdapter adapter = new LocalAnimationAdapter( - new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect, displayInfo, - durationScale, true /* isAppAnimation */, false /* isThumbnail */), + new WindowChangeAnimationSpec(mSurfaceFreezer.mFreezeBounds, mTmpRect, + displayInfo, durationScale, true /* isAppAnimation */, + false /* isThumbnail */), getSurfaceAnimationRunner()); - final AnimationAdapter thumbnailAdapter = mThumbnail != null - ? new LocalAnimationAdapter(new WindowChangeAnimationSpec(mTransitStartRect, - mTmpRect, displayInfo, durationScale, true /* isAppAnimation */, - true /* isThumbnail */), getSurfaceAnimationRunner()) + final AnimationAdapter thumbnailAdapter = mSurfaceFreezer.mSnapshot != null + ? new LocalAnimationAdapter(new WindowChangeAnimationSpec( + mSurfaceFreezer.mFreezeBounds, mTmpRect, displayInfo, durationScale, + true /* isAppAnimation */, true /* isThumbnail */), getSurfaceAnimationRunner()) : null; resultAdapters = new Pair<>(adapter, thumbnailAdapter); mTransit = transit; @@ -2140,7 +2173,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets, surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this); if (a != null) { - if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this); + if (a != null) { + // Setup the maximum app transition duration to prevent malicious app may set a long + // animation duration or infinite repeat counts for the app transition through + // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition. + a.restrictDuration(MAX_APP_TRANSITION_DURATION); + } + if (DEBUG_ANIM) { + logWithStack(TAG, "Loaded animation " + a + " for " + this + + ", duration: " + ((a != null) ? a.getDuration() : 0)); + } final int containingWidth = frame.width(); final int containingHeight = frame.height(); a.initialize(containingWidth, containingHeight, width, height); @@ -2189,6 +2231,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< @Override public void onAnimationLeashLost(Transaction t) { mLastLayer = -1; + mSurfaceFreezer.unfreeze(t); reassignLayer(t); } @@ -2329,6 +2372,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< mSurfaceControl = sc; } + RemoteAnimationDefinition getRemoteAnimationDefinition() { + return null; + } + /** Cheap way of doing cast and instanceof. */ Task asTask() { return null; diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 240f56611c77..4ac809de2904 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -527,9 +527,9 @@ public abstract class WindowManagerInternal { /** * Hide IME using imeTargetWindow when requested. * - * @param displayId on which IME is shown + * @param imeTargetWindowToken token of the (IME target) window on which IME should be hidden. */ - public abstract void hideIme(int displayId); + public abstract void hideIme(IBinder imeTargetWindowToken); /** * Tell window manager about a package that should not be running with high refresh rate diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e0f8f0e9aee9..673e7e0d241e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -42,7 +42,6 @@ import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIV import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; -import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; @@ -59,7 +58,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CO import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; @@ -214,7 +212,6 @@ import android.view.IDisplayFoldListener; import android.view.IDisplayWindowInsetsController; import android.view.IDisplayWindowListener; import android.view.IDisplayWindowRotationController; -import android.view.IDockedStackListener; import android.view.IInputFilter; import android.view.IOnKeyguardExitResult; import android.view.IPinnedStackListener; @@ -1636,14 +1633,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - // If the window is being added to a stack that's currently adjusted for IME, - // make sure to apply the same adjust to this new window. - win.applyAdjustForImeIfNeeded(); - - if (type == TYPE_DOCK_DIVIDER) { - mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win); - } - final WindowStateAnimator winAnimator = win.mWinAnimator; winAnimator.mEnterAnimationPending = true; winAnimator.mEnteringAnimation = true; @@ -1656,23 +1645,8 @@ public class WindowManagerService extends IWindowManager.Stub prepareNoneTransitionForRelaunching(activity); } - final DisplayFrames displayFrames = displayContent.mDisplayFrames; - // TODO: Not sure if onDisplayInfoUpdated() call is needed. - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); - displayFrames.onDisplayInfoUpdated(displayInfo, - displayContent.calculateDisplayCutoutForRotation(displayInfo.rotation)); - final Rect taskBounds; - final boolean floatingStack; - if (activity != null && activity.getTask() != null) { - taskBounds = mTmpRect; - tokenActivity.getTask().getBounds(mTmpRect); - floatingStack = activity.getTask().isFloating(); - } else { - taskBounds = null; - floatingStack = false; - } - if (displayPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, floatingStack, - outFrame, outContentInsets, outStableInsets, outDisplayCutout)) { + if (displayPolicy.getLayoutHint(win.mAttrs, token, outFrame, outContentInsets, + outStableInsets, outDisplayCutout)) { res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS; } outInsetsState.set(win.getInsetsState(), @@ -2816,16 +2790,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - void setDockedStackCreateStateLocked(int mode, Rect bounds) { - mDockedStackCreateMode = mode; - mDockedStackCreateBounds = bounds; - } - - void checkSplitScreenMinimizedChanged(boolean animate) { - final DisplayContent displayContent = getDefaultDisplayContentLocked(); - displayContent.getDockedDividerController().checkMinimizeChanged(animate); - } - boolean isValidPictureInPictureAspectRatio(DisplayContent displayContent, float aspectRatio) { return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio( aspectRatio); @@ -3295,10 +3259,6 @@ public class WindowManagerService extends IWindowManager.Stub // Notify whether the docked stack exists for the current user final DisplayContent displayContent = getDefaultDisplayContentLocked(); - final ActivityStack stack = - displayContent.getRootSplitScreenPrimaryTask(); - displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged( - stack != null && stack.hasTaskForUser(newUserId)); mRoot.forAllDisplays(dc -> dc.mAppTransition.setCurrentUser(newUserId)); @@ -4687,7 +4647,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int RESET_ANR_MESSAGE = 38; public static final int WALLPAPER_DRAW_PENDING_TIMEOUT = 39; - public static final int UPDATE_DOCKED_STACK_DIVIDER = 41; + public static final int UPDATE_MULTI_WINDOW_STACKS = 41; public static final int WINDOW_REPLACEMENT_TIMEOUT = 46; @@ -4832,7 +4792,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { // Since we're holding both mWindowMap and mAnimator we don't need to // hold mAnimator.mLayoutToAnim. - if (mAnimator.isAnimating() || mAnimator.isAnimationScheduled()) { + if (mAnimator.isAnimationScheduled()) { // If we are animating, don't do the gc now but // delay a bit so we don't interrupt the animation. sendEmptyMessageDelayed(H.FORCE_GC, 2000); @@ -4994,11 +4954,10 @@ public class WindowManagerService extends IWindowManager.Stub } break; } - case UPDATE_DOCKED_STACK_DIVIDER: { + case UPDATE_MULTI_WINDOW_STACKS: { synchronized (mGlobalLock) { final DisplayContent displayContent = getDefaultDisplayContentLocked(); if (displayContent != null) { - displayContent.getDockedDividerController().reevaluateVisibility(false); displayContent.adjustForImeIfNeeded(); } } @@ -6551,11 +6510,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public int getDockedStackSide() { - synchronized (mGlobalLock) { - final ActivityStack dockedStack = getDefaultDisplayContentLocked() - .getRootSplitScreenPrimaryTask(); - return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(); - } + return 0; } void setDockedStackResizing(boolean resizing) { @@ -6572,14 +6527,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) { - synchronized (mGlobalLock) { - getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer( - visible, targetWindowingMode, alpha); - } - } - void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) { synchronized (mGlobalLock) { mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays; @@ -6598,17 +6545,6 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void registerDockedStackListener(IDockedStackListener listener) { - mAtmInternal.enforceCallerIsRecentsOrHasPermission(REGISTER_WINDOW_MANAGER_LISTENERS, - "registerDockedStackListener()"); - synchronized (mGlobalLock) { - // TODO(multi-display): The listener is registered on the default display only. - getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener( - listener); - } - } - - @Override public void registerPinnedStackListener(int displayId, IPinnedStackListener listener) { if (!checkCallingPermission(REGISTER_WINDOW_MANAGER_LISTENERS, "registerPinnedStackListener()")) { @@ -7490,27 +7426,28 @@ public class WindowManagerService extends IWindowManager.Stub return; } imeTarget = imeTarget.getImeControlTarget(); - - final int displayId = imeTarget.getDisplayId(); - mRoot.getDisplayContent(displayId).getInsetsStateController().getImeSourceProvider() + imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider() .scheduleShowImePostLayout(imeTarget); } } @Override - public void hideIme(int displayId) { + public void hideIme(IBinder imeTargetWindowToken) { synchronized (mGlobalLock) { - final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc != null) { - InsetsControlTarget imeControlTarget = dc.mInputMethodControlTarget; - if (imeControlTarget == null) { - return; - } - // If there was a pending IME show(), reset it as IME has been - // requested to be hidden. - dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout(); - imeControlTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */); + WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); + if (imeTarget == null) { + // The target window no longer exists. + return; + } + final DisplayContent dc = imeTarget.getImeControlTarget().getDisplayContent(); + // If there was a pending IME show(), reset it as IME has been + // requested to be hidden. + dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout(); + if (dc.mInputMethodControlTarget == null) { + return; } + dc.mInputMethodControlTarget.hideInsets( + WindowInsets.Type.ime(), true /* fromIme */); } } @@ -8084,27 +8021,8 @@ public class WindowManagerService extends IWindowManager.Stub + "could not be found!"); } final WindowToken windowToken = dc.getWindowToken(attrs.token); - final ActivityRecord activity; - if (windowToken != null && windowToken.asActivityRecord() != null) { - activity = windowToken.asActivityRecord(); - } else { - activity = null; - } - final Rect taskBounds; - final boolean floatingStack; - if (activity != null && activity.getTask() != null) { - final Task task = activity.getTask(); - taskBounds = new Rect(); - task.getBounds(taskBounds); - floatingStack = task.isFloating(); - } else { - taskBounds = null; - floatingStack = false; - } - final DisplayFrames displayFrames = dc.mDisplayFrames; - final DisplayPolicy policy = dc.getDisplayPolicy(); - policy.getLayoutHintLw(attrs, taskBounds, displayFrames, floatingStack, - new Rect(), outContentInsets, outStableInsets, displayCutout); + dc.getDisplayPolicy().getLayoutHint(attrs, windowToken, mTmpRect /* outFrame */, + outContentInsets, outStableInsets, displayCutout); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 37597fbc7c45..805ef094e710 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1128,7 +1128,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } } else if (mAttrs.type == TYPE_DOCK_DIVIDER) { - dc.getDockedDividerController().positionDockedStackedDivider(windowFrames.mFrame); windowFrames.mContentFrame.set(windowFrames.mFrame); if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) { mMovedByResize = true; @@ -1449,6 +1448,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + /** @return The display frames in use by this window. */ DisplayFrames getDisplayFrames(DisplayFrames originalFrames) { final DisplayFrames diplayFrames = mToken.getFixedRotationTransformDisplayFrames(); if (diplayFrames != null) { @@ -1937,13 +1937,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // animating... let's do something. final int left = mWindowFrames.mFrame.left; final int top = mWindowFrames.mFrame.top; - final Task task = getTask(); - final boolean adjustedForMinimizedDockOrIme = task != null - && (task.getStack().isAdjustedForMinimizedDockedStack() - || task.getStack().isAdjustedForIme()); if (mToken.okToAnimate() && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0 - && !isDragResizing() && !adjustedForMinimizedDockOrIme + && !isDragResizing() && getWindowConfiguration().hasMovementAnimations() && !mWinAnimator.mLastHidden && !mSeamlesslyRotated) { @@ -2250,15 +2246,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } final ActivityStack stack = getRootTask(); - if (stack != null && stack.shouldIgnoreInput()) { + if (stack != null && !stack.isFocusable()) { // Ignore when the stack shouldn't receive input event. // (i.e. the minimized stack in split screen mode.) return false; } - if (PixelFormat.formatHasAlpha(mAttrs.format)) { - // Support legacy use cases where transparent windows can still be ime target with - // FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set. + if (PixelFormat.formatHasAlpha(mAttrs.format) && mAttrs.alpha == 0) { + // Support legacy use cases where completely transparent windows can still be ime target + // with FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set. // Certain apps listen for IME insets using transparent windows and ADJUST_NOTHING to // manually synchronize app content to IME animation b/144619551. // TODO(b/145812508): remove this once new focus management is complete b/141738570 @@ -2412,13 +2408,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - void applyAdjustForImeIfNeeded() { - final Task task = getTask(); - if (task != null && task.getStack() != null && task.getStack().isAdjustedForIme()) { - task.getStack().applyAdjustForImeIfNeeded(task); - } - } - @Override void switchUser(int userId) { super.switchUser(userId); @@ -3507,8 +3496,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP */ void notifyInsetsChanged() { try { - mClient.insetsChanged( - getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this)); + mClient.insetsChanged(getInsetsState()); } catch (RemoteException e) { Slog.w(TAG, "Failed to deliver inset state change w=" + this, e); } @@ -3518,9 +3506,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public void notifyInsetsControlChanged() { final InsetsStateController stateController = getDisplayContent().getInsetsStateController(); - final InsetsPolicy policy = getDisplayContent().getInsetsPolicy(); try { - mClient.insetsControlChanged(policy.getInsetsForDispatch(this), + mClient.insetsControlChanged(getInsetsState(), stateController.getControlsForDispatch(this)); } catch (RemoteException e) { Slog.w(TAG, "Failed to deliver inset state change", e); @@ -4308,10 +4295,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - if (mAttrs.type == TYPE_INPUT_METHOD) { - getDisplayContent().mDividerControllerLocked.resetImeHideRequested(); - } - return true; } diff --git a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java index 0c09c8828682..d02f79f3ad16 100644 --- a/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java +++ b/services/core/java/com/android/server/wm/utils/RotationAnimationUtils.java @@ -26,6 +26,8 @@ import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; +import java.util.Arrays; + /** Helper functions for the {@link com.android.server.wm.ScreenRotationAnimation} class*/ public class RotationAnimationUtils { @@ -35,31 +37,35 @@ public class RotationAnimationUtils { * luminance at the borders of the bitmap * @return the average luminance of all the pixels at the borders of the bitmap */ - public static float getAvgBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) { + public static float getMedianBorderLuma(GraphicBuffer graphicBuffer, ColorSpace colorSpace) { Bitmap hwBitmap = Bitmap.wrapHardwareBuffer(graphicBuffer, colorSpace); if (hwBitmap == null) { return 0; } Bitmap swaBitmap = hwBitmap.copy(Bitmap.Config.ARGB_8888, false); - float totalLuma = 0; int height = swaBitmap.getHeight(); int width = swaBitmap.getWidth(); + float[] borderLumas = new float[2 * width + 2 * height]; int i; - for (i = 0; i < width; i++) { - totalLuma += swaBitmap.getColor(i, 0).luminance(); - totalLuma += swaBitmap.getColor(i, height - 1).luminance(); + int index = 0; + for (i = 0; i < width; i++, index += 2) { + borderLumas[index] = swaBitmap.getColor(i, 0).luminance(); + borderLumas[index + 1] = swaBitmap.getColor(i, height - 1).luminance(); } - for (i = 0; i < height; i++) { - totalLuma += swaBitmap.getColor(0, i).luminance(); - totalLuma += swaBitmap.getColor(width - 1, i).luminance(); + for (i = 0; i < height; i++, index += 2) { + borderLumas[index] = swaBitmap.getColor(0, i).luminance(); + borderLumas[index + 1] = swaBitmap.getColor(width - 1, i).luminance(); } - return totalLuma / (2 * width + 2 * height); + // Oh, is this too simple and inefficient for you? + // How about implementing a O(n) solution? https://en.wikipedia.org/wiki/Median_of_medians + Arrays.sort(borderLumas); + return borderLumas[borderLumas.length / 2]; } /** * Gets the average border luma by taking a screenshot of the {@param surfaceControl}. - * @see #getAvgBorderLuma(GraphicBuffer, ColorSpace) + * @see #getMedianBorderLuma(GraphicBuffer, ColorSpace) */ public static float getLumaOfSurfaceControl(Display display, SurfaceControl surfaceControl) { if (surfaceControl == null) { @@ -75,7 +81,7 @@ public class RotationAnimationUtils { return 0; } - return RotationAnimationUtils.getAvgBorderLuma(buffer.getGraphicBuffer(), + return RotationAnimationUtils.getMedianBorderLuma(buffer.getGraphicBuffer(), buffer.getColorSpace()); } diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 5a8e25e4cf1c..05aa3594eb68 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -355,10 +355,11 @@ static jintArray vibratorGetSupportedEffects(JNIEnv *env, jclass) { } static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength, - jobject vibration) { + jobject vibration, jboolean withCallback) { if (auto hal = getHal<aidl::IVibrator>()) { int32_t lengthMs; - sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration); + sp<AidlVibratorCallback> effectCallback = + (withCallback != JNI_FALSE ? new AidlVibratorCallback(env, vibration) : nullptr); aidl::Effect effectType(static_cast<aidl::Effect>(effect)); aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength)); @@ -478,24 +479,24 @@ static void vibratorAlwaysOnDisable(JNIEnv* env, jclass, jlong id) { } static const JNINativeMethod method_table[] = { - { "vibratorExists", "()Z", (void*)vibratorExists }, - { "vibratorInit", "()V", (void*)vibratorInit }, - { "vibratorOn", "(J)V", (void*)vibratorOn }, - { "vibratorOff", "()V", (void*)vibratorOff }, - { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl}, - { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude}, - { "vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;)J", - (void*)vibratorPerformEffect}, - { "vibratorPerformComposedEffect", - "([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/VibratorService$Vibration;)V", - (void*)vibratorPerformComposedEffect}, - { "vibratorGetSupportedEffects", "()[I", - (void*)vibratorGetSupportedEffects}, - { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl}, - { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl}, - { "vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities}, - { "vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable}, - { "vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable}, + {"vibratorExists", "()Z", (void*)vibratorExists}, + {"vibratorInit", "()V", (void*)vibratorInit}, + {"vibratorOn", "(J)V", (void*)vibratorOn}, + {"vibratorOff", "()V", (void*)vibratorOff}, + {"vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl}, + {"vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude}, + {"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J", + (void*)vibratorPerformEffect}, + {"vibratorPerformComposedEffect", + "([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/" + "VibratorService$Vibration;)V", + (void*)vibratorPerformComposedEffect}, + {"vibratorGetSupportedEffects", "()[I", (void*)vibratorGetSupportedEffects}, + {"vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl}, + {"vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl}, + {"vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities}, + {"vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable}, + {"vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable}, }; int register_android_server_VibratorService(JNIEnv *env) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 440b779b8566..36c0659c9768 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4674,22 +4674,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return getUserDataUnchecked(userHandle).mAdminList; } ArrayList<ActiveAdmin> admins = new ArrayList<>(); - for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); - if (userInfo.id == userHandle) { - admins.addAll(policy.mAdminList); - } else if (userInfo.isManagedProfile()) { - // For managed profiles, policies set on the parent profile will be included - for (int i = 0; i < policy.mAdminList.size(); i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (admin.hasParentActiveAdmin()) { - admins.add(admin.getParentActiveAdmin()); + mInjector.binderWithCleanCallingIdentity(() -> { + for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) { + DevicePolicyData policy = getUserDataUnchecked(userInfo.id); + if (userInfo.id == userHandle) { + admins.addAll(policy.mAdminList); + } else if (userInfo.isManagedProfile()) { + // For managed profiles, policies set on the parent profile will be included + for (int i = 0; i < policy.mAdminList.size(); i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.hasParentActiveAdmin()) { + admins.add(admin.getParentActiveAdmin()); + } } + } else { + Slog.w(LOG_TAG, "Unknown user type: " + userInfo); } - } else { - Slog.w(LOG_TAG, "Unknown user type: " + userInfo); } - } + }); return admins; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ff8c20940c73..c1ac55f88a9d 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -394,6 +394,7 @@ public final class SystemServer { mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1; mRuntimeStartElapsedTime = SystemClock.elapsedRealtime(); mRuntimeStartUptime = SystemClock.uptimeMillis(); + Process.setStartTimes(mRuntimeStartElapsedTime, mRuntimeStartUptime); // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot // We don't use "mStartCount > 1" here because it'll be wrong on a FDE device. diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java index 5d7f4e9e1c9d..983a639776f6 100644 --- a/services/people/java/com/android/server/people/PeopleService.java +++ b/services/people/java/com/android/server/people/PeopleService.java @@ -17,6 +17,7 @@ package com.android.server.people; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionSessionId; @@ -145,14 +146,15 @@ public class PeopleService extends SystemService { mDataManager.pruneDataForUser(userId, signal); } + @Nullable @Override - public byte[] backupConversationInfos(@UserIdInt int userId) { - return new byte[0]; + public byte[] getBackupPayload(@UserIdInt int userId) { + return mDataManager.getBackupPayload(userId); } @Override - public void restoreConversationInfos(@UserIdInt int userId, @NonNull String key, - @NonNull byte[] payload) { + public void restore(@UserIdInt int userId, @NonNull byte[] payload) { + mDataManager.restore(userId, payload); } @VisibleForTesting diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java index 41bc3611e085..dc3fa2a048f6 100644 --- a/services/people/java/com/android/server/people/data/ConversationInfo.java +++ b/services/people/java/com/android/server/people/data/ConversationInfo.java @@ -24,6 +24,7 @@ import android.content.LocusIdProto; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutInfo.ShortcutFlags; import android.net.Uri; +import android.text.TextUtils; import android.util.Slog; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; @@ -31,6 +32,10 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.Preconditions; import com.android.server.people.ConversationInfoProto; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -280,6 +285,25 @@ public class ConversationInfo { } } + @Nullable + byte[] getBackupPayload() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos); + try { + out.writeUTF(mShortcutId); + out.writeUTF(mLocusId != null ? mLocusId.getId() : ""); + out.writeUTF(mContactUri != null ? mContactUri.toString() : ""); + out.writeUTF(mNotificationChannelId != null ? mNotificationChannelId : ""); + out.writeInt(mShortcutFlags); + out.writeInt(mConversationFlags); + out.writeUTF(mContactPhoneNumber != null ? mContactPhoneNumber : ""); + } catch (IOException e) { + Slog.e(TAG, "Failed to write fields to backup payload.", e); + return null; + } + return baos.toByteArray(); + } + /** Reads from {@link ProtoInputStream} and constructs a {@link ConversationInfo}. */ @NonNull static ConversationInfo readFromProto(@NonNull ProtoInputStream protoInputStream) @@ -331,6 +355,37 @@ public class ConversationInfo { return builder.build(); } + @Nullable + static ConversationInfo readFromBackupPayload(@NonNull byte[] payload) { + ConversationInfo.Builder builder = new ConversationInfo.Builder(); + DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload)); + try { + builder.setShortcutId(in.readUTF()); + String locusId = in.readUTF(); + if (!TextUtils.isEmpty(locusId)) { + builder.setLocusId(new LocusId(locusId)); + } + String contactUri = in.readUTF(); + if (!TextUtils.isEmpty(contactUri)) { + builder.setContactUri(Uri.parse(contactUri)); + } + String notificationChannelId = in.readUTF(); + if (!TextUtils.isEmpty(notificationChannelId)) { + builder.setNotificationChannelId(notificationChannelId); + } + builder.setShortcutFlags(in.readInt()); + builder.setConversationFlags(in.readInt()); + String contactPhoneNumber = in.readUTF(); + if (!TextUtils.isEmpty(contactPhoneNumber)) { + builder.setContactPhoneNumber(contactPhoneNumber); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to read conversation info fields from backup payload.", e); + return null; + } + return builder.build(); + } + /** * Builder class for {@link ConversationInfo} objects. */ diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java index 89c4972c8ef4..2f2a95cb0a6c 100644 --- a/services/people/java/com/android/server/people/data/ConversationStore.java +++ b/services/people/java/com/android/server/people/data/ConversationStore.java @@ -31,6 +31,10 @@ import com.android.server.people.ConversationInfosProto; import com.google.android.collect.Lists; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -48,6 +52,8 @@ class ConversationStore { private static final String CONVERSATIONS_FILE_NAME = "conversations"; + private static final int CONVERSATION_INFOS_END_TOKEN = -1; + // Shortcut ID -> Conversation Info @GuardedBy("this") private final Map<String, ConversationInfo> mConversationInfoMap = new ArrayMap<>(); @@ -195,6 +201,51 @@ class ConversationStore { mConversationInfosProtoDiskReadWriter.deleteConversationsFile(); } + @Nullable + synchronized byte[] getBackupPayload() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream conversationInfosOut = new DataOutputStream(baos); + for (ConversationInfo conversationInfo : mConversationInfoMap.values()) { + byte[] backupPayload = conversationInfo.getBackupPayload(); + if (backupPayload == null) { + continue; + } + try { + conversationInfosOut.writeInt(backupPayload.length); + conversationInfosOut.write(backupPayload); + } catch (IOException e) { + Slog.e(TAG, "Failed to write conversation info to backup payload.", e); + return null; + } + } + try { + conversationInfosOut.writeInt(CONVERSATION_INFOS_END_TOKEN); + } catch (IOException e) { + Slog.e(TAG, "Failed to write conversation infos end token to backup payload.", e); + return null; + } + return baos.toByteArray(); + } + + synchronized void restore(@NonNull byte[] payload) { + DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload)); + try { + for (int conversationInfoSize = in.readInt(); + conversationInfoSize != CONVERSATION_INFOS_END_TOKEN; + conversationInfoSize = in.readInt()) { + byte[] conversationInfoPayload = new byte[conversationInfoSize]; + in.readFully(conversationInfoPayload, 0, conversationInfoSize); + ConversationInfo conversationInfo = ConversationInfo.readFromBackupPayload( + conversationInfoPayload); + if (conversationInfo != null) { + addOrUpdate(conversationInfo); + } + } + } catch (IOException e) { + Slog.e(TAG, "Failed to read conversation info from payload.", e); + } + } + @MainThread private synchronized void updateConversationsInMemory( @NonNull ConversationInfo conversationInfo) { diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index 3a34c6a6be95..e4ce6bafff31 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -334,6 +334,25 @@ public class DataManager { }); } + /** Retrieves a backup payload blob for specified user id. */ + @Nullable + public byte[] getBackupPayload(@UserIdInt int userId) { + UserData userData = getUnlockedUserData(userId); + if (userData == null) { + return null; + } + return userData.getBackupPayload(); + } + + /** Attempts to restore data for the specified user id. */ + public void restore(@UserIdInt int userId, @NonNull byte[] payload) { + UserData userData = getUnlockedUserData(userId); + if (userData == null) { + return; + } + userData.restore(payload); + } + private int mimeTypeToShareEventType(String mimeType) { if (mimeType.startsWith("text/")) { return Event.TYPE_SHARE_TEXT; diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java index 35d245fc8d10..3e4c992ce70b 100644 --- a/services/people/java/com/android/server/people/data/PackageData.java +++ b/services/people/java/com/android/server/people/data/PackageData.java @@ -26,6 +26,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.LocusId; +import android.os.FileUtils; import android.text.TextUtils; import android.util.ArrayMap; @@ -251,5 +252,6 @@ public class PackageData { void onDestroy() { mEventStore.onDestroy(); mConversationStore.onDestroy(); + FileUtils.deleteContentsAndDir(mPackageDataDir); } } diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java index 0f8b91bfa2b1..ed8c595ab42a 100644 --- a/services/people/java/com/android/server/people/data/UserData.java +++ b/services/people/java/com/android/server/people/data/UserData.java @@ -22,8 +22,14 @@ import android.annotation.UserIdInt; import android.os.Environment; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.Slog; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; +import java.io.IOException; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Consumer; @@ -31,6 +37,10 @@ import java.util.function.Consumer; /** The data associated with a user profile. */ class UserData { + private static final String TAG = UserData.class.getSimpleName(); + + private static final int CONVERSATIONS_END_TOKEN = -1; + private final @UserIdInt int mUserId; private final File mPerUserPeopleDataDir; @@ -125,6 +135,48 @@ class UserData { return mDefaultSmsApp != null ? getPackageData(mDefaultSmsApp) : null; } + @Nullable + byte[] getBackupPayload() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos); + for (PackageData packageData : mPackageDataMap.values()) { + try { + byte[] conversationsBackupPayload = + packageData.getConversationStore().getBackupPayload(); + out.writeInt(conversationsBackupPayload.length); + out.write(conversationsBackupPayload); + out.writeUTF(packageData.getPackageName()); + } catch (IOException e) { + Slog.e(TAG, "Failed to write conversations to backup payload.", e); + return null; + } + } + try { + out.writeInt(CONVERSATIONS_END_TOKEN); + } catch (IOException e) { + Slog.e(TAG, "Failed to write conversations end token to backup payload.", e); + return null; + } + return baos.toByteArray(); + } + + void restore(@NonNull byte[] payload) { + DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload)); + try { + for (int conversationsPayloadSize = in.readInt(); + conversationsPayloadSize != CONVERSATIONS_END_TOKEN; + conversationsPayloadSize = in.readInt()) { + byte[] conversationsPayload = new byte[conversationsPayloadSize]; + in.readFully(conversationsPayload, 0, conversationsPayloadSize); + String packageName = in.readUTF(); + getOrCreatePackageData(packageName).getConversationStore().restore( + conversationsPayload); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to restore conversations from backup payload.", e); + } + } + private PackageData createPackageData(String packageName) { return new PackageData(packageName, mUserId, this::isDefaultDialer, this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir); diff --git a/services/robotests/Android.bp b/services/robotests/Android.bp index d2f86eeabb47..602e4e1ac8ce 100644 --- a/services/robotests/Android.bp +++ b/services/robotests/Android.bp @@ -26,6 +26,8 @@ android_app { "services.core", "services.net", ], + + libs: ["ike-stubs"], } //################################################################## diff --git a/services/robotests/backup/Android.bp b/services/robotests/backup/Android.bp index ef0ca66610c9..5160eae060f6 100644 --- a/services/robotests/backup/Android.bp +++ b/services/robotests/backup/Android.bp @@ -28,6 +28,8 @@ android_app { "services.core", "services.net", ], + + libs: ["ike-stubs"], } //################################################################## diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java index 00495f3ec02d..730f303f036a 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java @@ -107,6 +107,7 @@ public class JobSchedulerServiceTest { .when(() -> LocalServices.getService(AppStandbyInternal.class)); doReturn(mock(UsageStatsManagerInternal.class)) .when(() -> LocalServices.getService(UsageStatsManagerInternal.class)); + when(mContext.getString(anyInt())).thenReturn("some_test_string"); // Called in BackgroundJobsController constructor. doReturn(mock(AppStateTracker.class)) .when(() -> LocalServices.getService(AppStateTracker.class)); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index 9a7d6ea52d98..7ce0296f3691 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -189,6 +189,7 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { public void testOnSystemActionsChanged() throws Exception { setupAccessibilityServiceConnection(); mA11yms.notifySystemActionsChangedLocked(mUserState); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); verify(mMockServiceClient).onSystemActionsChanged(); } } diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index 407f67e2fd8e..44f4ccf69cdd 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertThrows; +import android.app.compat.ChangeIdStateCache; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -74,6 +75,7 @@ public class CompatConfigTest { // Assume userdebug/eng non-final build when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); when(mBuildClassifier.isFinalBuild()).thenReturn(false); + ChangeIdStateCache.disable(); } @Test diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index 4a686ee6a081..53b90f2b01db 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -62,6 +62,7 @@ public class PlatformCompatTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + android.app.compat.ChangeIdStateCache.disable(); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow( new PackageManager.NameNotFoundException()); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index 40b0e7114cc9..de2addffa2c5 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -39,14 +39,13 @@ import androidx.test.filters.SmallTest; import com.android.frameworks.servicestests.R; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.Set; -// TODO (b/149818286): Fix old test cases and put the whole test into presubmit. +@Presubmit public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { private static final String USER_TYPE_EMPTY = ""; @@ -78,7 +77,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { // Create the legacy owners & policies file. DpmTestUtils.writeToFile( - (new File(getServices().dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(), + (new File(getServices().dataDir, "device_owner.xml")).getAbsoluteFile(), DpmTestUtils.readAsset(mRealTestContext, "DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml")); @@ -193,8 +192,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { // Check the new owner restrictions. DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( - UserManager.DISALLOW_ADD_USER, - UserManager.DISALLOW_ADD_MANAGED_PROFILE + UserManager.DISALLOW_ADD_USER ), dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()); @@ -216,7 +214,7 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { // Create the legacy owners & policies file. DpmTestUtils.writeToFile( - (new File(getServices().dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(), + (new File(getServices().dataDir, "device_owner.xml")).getAbsoluteFile(), DpmTestUtils.readAsset(mRealTestContext, "DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml")); @@ -346,7 +344,6 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { assertTrue(alreadySet.contains(UserManager.DISALLOW_BLUETOOTH_SHARING)); } - @Presubmit @SmallTest public void testCompMigrationUnAffiliated_skipped() throws Exception { prepareAdmin1AsDo(); @@ -359,7 +356,6 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { assertTrue(dpms.mOwners.hasDeviceOwner()); } - @Presubmit @SmallTest public void testCompMigrationAffiliated() throws Exception { prepareAdmin1AsDo(); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 853151f8a0de..5ad81b2c4506 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -66,7 +66,6 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi * Overrides {@link #Owners} for dependency injection. */ public static class OwnersTestable extends Owners { - public static final String LEGACY_FILE = "legacy.xml"; public OwnersTestable(MockSystemServices services) { super(services.userManager, services.userManagerInternal, diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index feae1e173f52..08bd1ee3c389 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -144,4 +144,49 @@ public class DisplayModeDirectorTest { Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60); } + + @Test + public void testBrightnessHasLowerPriorityThanUser() { + assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE); + assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE); + + int displayId = 0; + DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90); + SparseArray<Vote> votes = new SparseArray<>(); + SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>(); + votesByDisplay.put(displayId, votes); + votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90)); + votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60)); + director.injectVotesByDisplay(votesByDisplay); + DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); + Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); + + votes.clear(); + votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90)); + votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90)); + director.injectVotesByDisplay(votesByDisplay); + desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); + Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90); + + + votes.clear(); + votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90)); + votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60)); + director.injectVotesByDisplay(votesByDisplay); + desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90); + Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90); + + votes.clear(); + votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60)); + votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90)); + director.injectVotesByDisplay(votesByDisplay); + desiredSpecs = director.getDesiredDisplayModeSpecs(displayId); + Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60); + Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60); + + + } } diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index be873bdd095d..d9101bf6a48b 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -60,6 +60,7 @@ import android.content.res.Resources; import android.net.Uri; import android.os.Handler; import android.os.Message; +import android.provider.Settings; import androidx.test.InstrumentationRegistry; @@ -119,7 +120,6 @@ public class AppIntegrityManagerServiceImplTest { private static final String PLAY_STORE_PKG = "com.android.vending"; private static final String ADB_INSTALLER = "adb"; private static final String PLAY_STORE_CERT = "play_store_cert"; - private static final String ADB_CERT = ""; @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -137,11 +137,12 @@ public class AppIntegrityManagerServiceImplTest { @Mock Handler mHandler; + private final Context mRealContext = InstrumentationRegistry.getTargetContext(); + private PackageManager mSpyPackageManager; private File mTestApk; private File mTestApkTwoCerts; - private final Context mRealContext = InstrumentationRegistry.getTargetContext(); // under test private AppIntegrityManagerServiceImpl mService; @@ -163,8 +164,7 @@ public class AppIntegrityManagerServiceImplTest { mPackageManagerInternal, mRuleEvaluationEngine, mIntegrityFileManager, - mHandler, - /* checkIntegrityForRuleProviders= */ true); + mHandler); mSpyPackageManager = spy(mRealContext.getPackageManager()); // setup mocks to prevent NPE @@ -172,6 +172,9 @@ public class AppIntegrityManagerServiceImplTest { when(mMockContext.getResources()).thenReturn(mMockResources); when(mMockResources.getStringArray(anyInt())).thenReturn(new String[]{}); when(mIntegrityFileManager.initialized()).thenReturn(true); + // These are needed to override the Settings.Global.get result. + when(mMockContext.getContentResolver()).thenReturn(mRealContext.getContentResolver()); + setIntegrityCheckIncludesRuleProvider(true); } @After @@ -201,6 +204,7 @@ public class AppIntegrityManagerServiceImplTest { @Test public void updateRuleSet_notSystemApp() throws Exception { whitelistUsAsRuleProvider(); + makeUsSystemApp(false); Rule rule = new Rule( new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), @@ -411,14 +415,7 @@ public class AppIntegrityManagerServiceImplTest { public void verifierAsInstaller_skipIntegrityVerification() throws Exception { whitelistUsAsRuleProvider(); makeUsSystemApp(); - mService = - new AppIntegrityManagerServiceImpl( - mMockContext, - mPackageManagerInternal, - mRuleEvaluationEngine, - mIntegrityFileManager, - mHandler, - /* checkIntegrityForRuleProviders= */ false); + setIntegrityCheckIncludesRuleProvider(false); ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext, atLeastOnce()) @@ -460,12 +457,21 @@ public class AppIntegrityManagerServiceImplTest { } private void makeUsSystemApp() throws Exception { + makeUsSystemApp(true); + } + + private void makeUsSystemApp(boolean isSystemApp) throws Exception { PackageInfo packageInfo = mRealContext.getPackageManager().getPackageInfo(TEST_FRAMEWORK_PACKAGE, 0); - packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + if (isSystemApp) { + packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + } else { + packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM; + } doReturn(packageInfo) .when(mSpyPackageManager) .getPackageInfo(eq(TEST_FRAMEWORK_PACKAGE), anyInt()); + when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager); } private Intent makeVerificationIntent() throws Exception { @@ -492,4 +498,13 @@ public class AppIntegrityManagerServiceImplTest { intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, VERSION_CODE); return intent; } + + private void setIntegrityCheckIncludesRuleProvider(boolean shouldInclude) throws Exception { + int value = shouldInclude ? 1 : 0; + Settings.Global.putInt(mRealContext.getContentResolver(), + Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, value); + assertThat(Settings.Global.getInt(mRealContext.getContentResolver(), + Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER, -1) == 1).isEqualTo( + shouldInclude); + } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java index 44d88d2b44d3..1cf8525eecdd 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -19,12 +19,16 @@ package com.android.server.locksettings; import static android.content.pm.UserInfo.FLAG_FULL; import static android.content.pm.UserInfo.FLAG_PRIMARY; import static android.content.pm.UserInfo.FLAG_PROFILE; +import static android.os.UserHandle.USER_SYSTEM; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -32,8 +36,10 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.testng.Assert.assertNull; import android.content.Context; +import android.content.ContextWrapper; import android.content.pm.UserInfo; import android.hardware.rebootescrow.IRebootEscrow; import android.os.RemoteException; @@ -49,6 +55,7 @@ import com.android.internal.widget.RebootEscrowListener; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.io.File; import java.util.ArrayList; @@ -76,16 +83,26 @@ public class RebootEscrowManagerTests { LockSettingsStorageTestable mStorage; + private MockableRebootEscrowInjected mInjected; private RebootEscrowManager mService; + public interface MockableRebootEscrowInjected { + int getBootCount(); + + void reportMetric(boolean success); + } + static class MockInjector extends RebootEscrowManager.Injector { private final IRebootEscrow mRebootEscrow; private final UserManager mUserManager; + private final MockableRebootEscrowInjected mInjected; - MockInjector(Context context, UserManager userManager, IRebootEscrow rebootEscrow) { + MockInjector(Context context, UserManager userManager, IRebootEscrow rebootEscrow, + MockableRebootEscrowInjected injected) { super(context); mRebootEscrow = rebootEscrow; mUserManager = userManager; + mInjected = injected; } @Override @@ -97,11 +114,21 @@ public class RebootEscrowManagerTests { public IRebootEscrow getRebootEscrow() { return mRebootEscrow; } + + @Override + public int getBootCount() { + return mInjected.getBootCount(); + } + + @Override + public void reportMetric(boolean success) { + mInjected.reportMetric(success); + } } @Before public void setUp_baseServices() throws Exception { - mContext = mock(Context.class); + mContext = new ContextWrapper(InstrumentationRegistry.getContext()); mUserManager = mock(UserManager.class); mCallbacks = mock(RebootEscrowManager.Callbacks.class); mRebootEscrow = mock(IRebootEscrow.class); @@ -119,8 +146,9 @@ public class RebootEscrowManagerTests { when(mCallbacks.isUserSecure(WORK_PROFILE_USER_ID)).thenReturn(true); when(mCallbacks.isUserSecure(NONSECURE_SECONDARY_USER_ID)).thenReturn(false); when(mCallbacks.isUserSecure(SECURE_SECONDARY_USER_ID)).thenReturn(true); - mService = new RebootEscrowManager(new MockInjector(mContext, mUserManager, mRebootEscrow), - mCallbacks, mStorage); + mInjected = mock(MockableRebootEscrowInjected.class); + mService = new RebootEscrowManager(new MockInjector(mContext, mUserManager, mRebootEscrow, + mInjected), mCallbacks, mStorage); } @Test @@ -160,7 +188,11 @@ public class RebootEscrowManagerTests { verify(mockListener).onPreparedForReboot(eq(true)); verify(mRebootEscrow, never()).storeKey(any()); + assertNull( + mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM)); assertTrue(mService.armRebootEscrowIfNeeded()); + assertNotNull( + mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM)); verify(mRebootEscrow).storeKey(any()); assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); @@ -180,7 +212,15 @@ public class RebootEscrowManagerTests { FAKE_AUTH_TOKEN); verify(mRebootEscrow, never()).storeKey(any()); + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertTrue(mStorage.hasRebootEscrow(SECURE_SECONDARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); + + assertNull( + mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM)); assertTrue(mService.armRebootEscrowIfNeeded()); + assertNotNull( + mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM)); verify(mRebootEscrow, times(1)).storeKey(any()); assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); @@ -200,4 +240,105 @@ public class RebootEscrowManagerTests { assertFalse(mService.armRebootEscrowIfNeeded()); verifyNoMoreInteractions(mRebootEscrow); } + + @Test + public void loadRebootEscrowDataIfAvailable_NothingAvailable_Success() throws Exception { + mService.loadRebootEscrowDataIfAvailable(); + } + + @Test + public void loadRebootEscrowDataIfAvailable_Success() throws Exception { + when(mInjected.getBootCount()).thenReturn(0); + + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mRebootEscrow); + mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + verify(mockListener).onPreparedForReboot(eq(true)); + + verify(mRebootEscrow, never()).storeKey(any()); + + ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class); + assertTrue(mService.armRebootEscrowIfNeeded()); + verify(mRebootEscrow).storeKey(keyByteCaptor.capture()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); + + // pretend reboot happens here + + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture()); + when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); + + mService.loadRebootEscrowDataIfAvailable(); + verify(mRebootEscrow).retrieveKey(); + assertTrue(metricsSuccessCaptor.getValue()); + } + + @Test + public void loadRebootEscrowDataIfAvailable_TooManyBootsInBetween_NoMetrics() throws Exception { + when(mInjected.getBootCount()).thenReturn(0); + + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mRebootEscrow); + mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + verify(mockListener).onPreparedForReboot(eq(true)); + + verify(mRebootEscrow, never()).storeKey(any()); + + ArgumentCaptor<byte[]> keyByteCaptor = ArgumentCaptor.forClass(byte[].class); + assertTrue(mService.armRebootEscrowIfNeeded()); + verify(mRebootEscrow).storeKey(keyByteCaptor.capture()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); + + // pretend reboot happens here + + when(mInjected.getBootCount()).thenReturn(10); + when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); + + mService.loadRebootEscrowDataIfAvailable(); + verify(mRebootEscrow).retrieveKey(); + verify(mInjected, never()).reportMetric(anyBoolean()); + } + + + @Test + public void loadRebootEscrowDataIfAvailable_RestoreUnsuccessful_Failure() throws Exception { + when(mInjected.getBootCount()).thenReturn(0); + + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mRebootEscrow); + mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + verify(mockListener).onPreparedForReboot(eq(true)); + + verify(mRebootEscrow, never()).storeKey(any()); + + assertTrue(mService.armRebootEscrowIfNeeded()); + verify(mRebootEscrow).storeKey(any()); + + assertTrue(mStorage.hasRebootEscrow(PRIMARY_USER_ID)); + assertFalse(mStorage.hasRebootEscrow(NONSECURE_SECONDARY_USER_ID)); + + // pretend reboot happens here. + + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture()); + when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]); + mService.loadRebootEscrowDataIfAvailable(); + verify(mRebootEscrow).retrieveKey(); + assertFalse(metricsSuccessCaptor.getValue()); + } } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt index 233e16c297a3..e08eea298aaf 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt +++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt @@ -24,6 +24,7 @@ import android.os.Process import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException +import java.lang.UnsupportedOperationException class OverlayActorEnforcerTests { companion object { @@ -159,7 +160,7 @@ class OverlayActorEnforcerTests { private val hasPermission: Boolean = false, private val overlayableInfo: OverlayableInfo? = null, private vararg val packageNames: String = arrayOf("com.test.actor.one") - ) : OverlayActorEnforcer.VerifyCallback { + ) : OverlayableInfoCallback { override fun getNamedActors() = if (isActor) { mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME)) @@ -169,7 +170,7 @@ class OverlayActorEnforcerTests { override fun getOverlayableForTarget( packageName: String, - targetOverlayableName: String?, + targetOverlayableName: String, userId: Int ) = overlayableInfo @@ -193,5 +194,9 @@ class OverlayActorEnforcerTests { throw SecurityException() } } + + override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean { + throw UnsupportedOperationException() + } } } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java index a428a97e51cd..cd7343235750 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -24,30 +24,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import android.annotation.NonNull; import android.content.om.OverlayInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.content.om.OverlayConfig; - -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; @RunWith(AndroidJUnit4.class) public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase { diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java index a753aac39c48..820e61cb0a08 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -23,10 +23,13 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.om.OverlayInfo; import android.content.om.OverlayInfo.State; +import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.util.ArraySet; +import androidx.annotation.Nullable; + import com.android.internal.content.om.OverlayConfig; import org.junit.Before; @@ -35,6 +38,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -281,8 +285,8 @@ class OverlayManagerServiceImplTestsBase { } } - static final class DummyPackageManagerHelper implements - OverlayManagerServiceImpl.PackageManagerHelper { + static final class DummyPackageManagerHelper implements PackageManagerHelper, + OverlayableInfoCallback { private final DummyDeviceState mState; private DummyPackageManagerHelper(DummyDeviceState state) { @@ -320,6 +324,35 @@ class OverlayManagerServiceImplTestsBase { .map(p -> getPackageInfo(p.packageName, p.userId)) .collect(Collectors.toList()); } + + @Nullable + @Override + public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, + @NonNull String targetOverlayableName, int userId) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public String[] getPackagesForUid(int uid) { + throw new UnsupportedOperationException(); + } + + @NonNull + @Override + public Map<String, Map<String, String>> getNamedActors() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) { + throw new UnsupportedOperationException(); + } + + @Override + public void enforcePermission(String permission, String message) throws SecurityException { + throw new UnsupportedOperationException(); + } } static class DummyIdmapManager extends IdmapManager { diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java index d138700f1d2a..4e63237a6091 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java @@ -284,6 +284,30 @@ public final class ConversationStoreTest { assertEquals(in2, out2); } + @Test + public void testBackupAndRestore() { + ConversationInfo in1 = buildConversationInfo(SHORTCUT_ID, LOCUS_ID, CONTACT_URI, + PHONE_NUMBER, NOTIFICATION_CHANNEL_ID); + ConversationInfo in2 = buildConversationInfo(SHORTCUT_ID_2, LOCUS_ID_2, CONTACT_URI_2, + PHONE_NUMBER_2, NOTIFICATION_CHANNEL_ID_2); + mConversationStore.addOrUpdate(in1); + mConversationStore.addOrUpdate(in2); + + byte[] backupPayload = mConversationStore.getBackupPayload(); + assertNotNull(backupPayload); + + ConversationStore conversationStore = new ConversationStore(mFile, + mMockScheduledExecutorService); + ConversationInfo out1 = conversationStore.getConversation(SHORTCUT_ID); + assertNull(out1); + + conversationStore.restore(backupPayload); + out1 = conversationStore.getConversation(SHORTCUT_ID); + ConversationInfo out2 = conversationStore.getConversation(SHORTCUT_ID_2); + assertEquals(in1, out1); + assertEquals(in2, out2); + } + private void resetConversationStore() { mFile.mkdir(); mMockScheduledExecutorService = new MockScheduledExecutorService(); diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index f0b7d206f2bf..e57df24d67cb 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -653,6 +653,33 @@ public final class DataManagerTest { assertTrue(activeTimeSlots.isEmpty()); } + @Test + public void testBackupAndRestoration() + throws IntentFilter.MalformedMimeTypeException { + mDataManager.onUserUnlocked(USER_ID_PRIMARY); + ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, + null); + AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut) + .build(); + AppTargetEvent appTargetEvent = + new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH) + .setLaunchLocation(ChooserActivity.LAUNCH_LOCATON_DIRECT_SHARE) + .build(); + IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg"); + + mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter); + byte[] payload = mDataManager.getBackupPayload(USER_ID_PRIMARY); + + DataManager dataManager = new DataManager(mContext, mInjector); + dataManager.onUserUnlocked(USER_ID_PRIMARY); + dataManager.restore(USER_ID_PRIMARY, payload); + ConversationInfo conversationInfo = dataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY) + .getConversationStore() + .getConversation(TEST_SHORTCUT_ID); + assertNotNull(conversationInfo); + assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID); + } + private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { LocalServices.removeServiceForTest(clazz); LocalServices.addService(clazz, mock); diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java index 30ab9cd2f875..dc30add1b383 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java @@ -117,7 +117,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { @SmallTest public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() { - mBatterySaverPolicy.setAccessibilityEnabledForTest(true); + mBatterySaverPolicy.setAccessibilityEnabled(true); testServiceDefaultValue_Off(ServiceType.VIBRATION); } @@ -339,4 +339,57 @@ public class BatterySaverPolicyTest extends AndroidTestCase { Policy.fromSettings(BATTERY_SAVER_CONSTANTS, "")); verifyBatterySaverConstantsUpdated(); } + + public void testCarModeChanges_Full() { + mBatterySaverPolicy.updateConstantsLocked( + "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF + + ",enable_night_mode=true", ""); + mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL); + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + assertTrue(mBatterySaverPolicy.getBatterySaverPolicy( + ServiceType.NIGHT_MODE).batterySaverEnabled); + + mBatterySaverPolicy.setCarModeEnabled(true); + + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isAnyOf(PowerManager.LOCATION_MODE_NO_CHANGE, + PowerManager.LOCATION_MODE_FOREGROUND_ONLY); + assertFalse(mBatterySaverPolicy.getBatterySaverPolicy( + ServiceType.NIGHT_MODE).batterySaverEnabled); + + mBatterySaverPolicy.setCarModeEnabled(false); + + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + assertTrue(mBatterySaverPolicy.getBatterySaverPolicy( + ServiceType.NIGHT_MODE).batterySaverEnabled); + } + + public void testCarModeChanges_Adaptive() { + mBatterySaverPolicy.setAdaptivePolicyLocked( + Policy.fromSettings( + "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF + + ",enable_night_mode=true", "")); + mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_ADAPTIVE); + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + assertTrue(mBatterySaverPolicy.getBatterySaverPolicy( + ServiceType.NIGHT_MODE).batterySaverEnabled); + + mBatterySaverPolicy.setCarModeEnabled(true); + + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isAnyOf(PowerManager.LOCATION_MODE_NO_CHANGE, + PowerManager.LOCATION_MODE_FOREGROUND_ONLY); + assertFalse(mBatterySaverPolicy.getBatterySaverPolicy( + ServiceType.NIGHT_MODE).batterySaverEnabled); + + mBatterySaverPolicy.setCarModeEnabled(false); + + assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode) + .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF); + assertTrue(mBatterySaverPolicy.getBatterySaverPolicy( + ServiceType.NIGHT_MODE).batterySaverEnabled); + } } diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java index c56034adb73d..06b5fe48c4cf 100644 --- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java +++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java @@ -60,6 +60,8 @@ import android.os.HwParcel; import android.os.IHwBinder; import android.os.IHwInterface; import android.os.RemoteException; +import android.os.SharedMemory; +import android.system.ErrnoException; import android.util.Pair; import org.junit.Before; @@ -71,6 +73,9 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.stubbing.Answer; +import java.io.FileDescriptor; +import java.nio.ByteBuffer; + @RunWith(Parameterized.class) public class SoundTriggerMiddlewareImplTest { private static final String TAG = "SoundTriggerMiddlewareImplTest"; @@ -104,12 +109,25 @@ public class SoundTriggerMiddlewareImplTest { return createSoundModel(SoundModelType.GENERIC); } + private static FileDescriptor byteArrayToFileDescriptor(byte[] data) { + try { + SharedMemory shmem = SharedMemory.create("", data.length); + ByteBuffer buffer = shmem.mapReadWrite(); + buffer.put(data); + return shmem.getFileDescriptor(); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } + private static SoundModel createSoundModel(int type) { SoundModel model = new SoundModel(); model.type = type; model.uuid = "12345678-2345-3456-4567-abcdef987654"; model.vendorUuid = "87654321-5432-6543-7654-456789fedcba"; - model.data = new byte[]{91, 92, 93, 94, 95}; + byte[] data = new byte[]{91, 92, 93, 94, 95}; + model.data = byteArrayToFileDescriptor(data); + model.dataSize = data.length; return model; } diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml index dab0a5f0e279..767857bf2de8 100644 --- a/services/tests/uiservicestests/AndroidManifest.xml +++ b/services/tests/uiservicestests/AndroidManifest.xml @@ -23,7 +23,6 @@ <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" /> - <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> diff --git a/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java b/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java index 1629ef00b65a..6e7df05e8afe 100644 --- a/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java +++ b/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java @@ -17,7 +17,7 @@ package com.android.internal.logging; /** - * A fake implementation of InstanceIdSequence that returns 0, 1, 2, ... + * A fake implementation of InstanceIdSequence that returns 1, 2, ... */ public class InstanceIdSequenceFake extends InstanceIdSequence { @@ -25,13 +25,13 @@ public class InstanceIdSequenceFake extends InstanceIdSequence { super(instanceIdMax); } - private int mNextId = 0; + private int mNextId = 1; @Override public InstanceId newInstanceId() { synchronized (this) { if (mNextId >= mInstanceIdMax) { - mNextId = 0; + mNextId = 1; } return newInstanceIdInternal(mNextId++); } diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index 22046a51d059..6a707eb36160 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -28,6 +28,8 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.os.Handler; import android.os.PowerManager; +import android.os.PowerManagerInternal; +import android.os.PowerSaveState; import android.os.RemoteException; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -42,6 +44,7 @@ import org.mockito.Mock; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; +import java.util.function.Consumer; import static android.app.UiModeManager.MODE_NIGHT_AUTO; import static android.app.UiModeManager.MODE_NIGHT_CUSTOM; @@ -79,29 +82,34 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { @Mock private Resources mResources; @Mock - TwilightManager mTwilightManager; + private TwilightManager mTwilightManager; @Mock - PowerManager.WakeLock mWakeLock; + private PowerManager.WakeLock mWakeLock; @Mock - AlarmManager mAlarmManager; + private AlarmManager mAlarmManager; @Mock - PowerManager mPowerManager; + private PowerManager mPowerManager; @Mock - TwilightState mTwilightState; + private TwilightState mTwilightState; + @Mock + PowerManagerInternal mLocalPowerManager; private BroadcastReceiver mScreenOffCallback; private BroadcastReceiver mTimeChangedCallback; private AlarmManager.OnAlarmListener mCustomListener; + private Consumer<PowerSaveState> mPowerSaveConsumer; @Before public void setUp() { initMocks(this); - mUiManagerService = new UiModeManagerService(mContext, - mWindowManager, mAlarmManager, mPowerManager, - mWakeLock, mTwilightManager, true); - mService = mUiManagerService.getService(); when(mContext.checkCallingOrSelfPermission(anyString())) .thenReturn(PackageManager.PERMISSION_GRANTED); + doAnswer(inv -> { + mPowerSaveConsumer = (Consumer<PowerSaveState>) inv.getArgument(1); + return null; + }).when(mLocalPowerManager).registerLowPowerModeObserver(anyInt(), any()); + when(mLocalPowerManager.getLowPowerState(anyInt())) + .thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(false).build()); when(mContext.getResources()).thenReturn(mResources); when(mContext.getContentResolver()).thenReturn(mContentResolver); when(mPowerManager.isInteractive()).thenReturn(true); @@ -127,6 +135,14 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { mCustomListener = () -> {}; return null; }).when(mAlarmManager).cancel(eq(mCustomListener)); + + mUiManagerService = new UiModeManagerService(mContext, + mWindowManager, mAlarmManager, mPowerManager, + mWakeLock, mTwilightManager, mLocalPowerManager, true); + try { + mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY); + } catch (SecurityException e) {/* ignore for permission denial */} + mService = mUiManagerService.getService(); } @Test @@ -151,6 +167,22 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { } @Test + public void autoNightModeSwitch_batterySaverOn() throws RemoteException { + mService.setNightMode(MODE_NIGHT_NO); + when(mTwilightState.isNight()).thenReturn(false); + mService.setNightMode(MODE_NIGHT_AUTO); + + // night NO + assertFalse(isNightModeActivated()); + + mPowerSaveConsumer.accept( + new PowerSaveState.Builder().setBatterySaverEnabled(true).build()); + + // night YES + assertTrue(isNightModeActivated()); + } + + @Test public void setAutoMode_clearCache() throws RemoteException { try { mService.setNightMode(MODE_NIGHT_AUTO); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index f029bc80480a..afd10ddb8ec2 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -846,6 +846,18 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } @Test + public void testPostSilently() throws Exception { + NotificationRecord r = getBuzzyNotification(); + r.setPostSilently(true); + + mService.buzzBeepBlinkLocked(r); + + verifyNeverBeep(); + assertFalse(r.isInterruptive()); + assertEquals(-1, r.getLastAudiblyAlertedMs()); + } + + @Test public void testGroupAlertSummarySilenceChild() throws Exception { NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java index a328568da7ed..b9ffd65ee20e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java @@ -22,8 +22,8 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.app.Notification; import android.app.NotificationChannel; @@ -33,6 +33,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.media.session.MediaSession; import android.os.Build; +import android.os.Process; import android.os.UserHandle; import android.provider.Settings; import android.service.notification.StatusBarNotification; @@ -140,7 +141,7 @@ public class NotificationComparatorTest extends UiServiceTestCase { Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID) .setStyle(new Notification.MediaStyle() - .setMediaSession(new MediaSession.Token(null))) + .setMediaSession(new MediaSession.Token(Process.myUid(), null))) .build(); mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2, pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId), diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java index 99b4fd98f9a8..b7bcbfb05531 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java @@ -64,7 +64,6 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { Context mContext; @Mock AlarmManager mAlarmManager; - TestFileAttrProvider mFileAttrProvider; NotificationHistoryDatabase mDataBase; @@ -103,11 +102,9 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { when(mContext.getUser()).thenReturn(getContext().getUser()); when(mContext.getPackageName()).thenReturn(getContext().getPackageName()); - mFileAttrProvider = new TestFileAttrProvider(); mRootDir = new File(mContext.getFilesDir(), "NotificationHistoryDatabaseTest"); - mDataBase = new NotificationHistoryDatabase( - mContext, mFileWriteHandler, mRootDir, mFileAttrProvider); + mDataBase = new NotificationHistoryDatabase(mContext, mFileWriteHandler, mRootDir); mDataBase.init(); } @@ -127,7 +124,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { // add 5 files with a creation date of "today" for (long i = cal.getTimeInMillis(); i >= 5; i--) { File file = mock(File.class); - mFileAttrProvider.creationDates.put(file, i); + when(file.getName()).thenReturn(String.valueOf(i)); AtomicFile af = new AtomicFile(file); expectedFiles.add(af); mDataBase.mHistoryFiles.addLast(af); @@ -137,7 +134,7 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { // Add 5 more files more than retainDays old for (int i = 5; i >= 0; i--) { File file = mock(File.class); - mFileAttrProvider.creationDates.put(file, cal.getTimeInMillis() - i); + when(file.getName()).thenReturn(String.valueOf(cal.getTimeInMillis() - i)); AtomicFile af = new AtomicFile(file); mDataBase.mHistoryFiles.addLast(af); } @@ -331,13 +328,4 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { verify(nh).removeConversationFromWrite("pkg", "convo"); verify(af, never()).startWrite(); } - - private class TestFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider { - public Map<File, Long> creationDates = new HashMap<>(); - - @Override - public long getCreationTime(File file) { - return creationDates.get(file); - } - } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index da0e03dff65a..dc8d0104353a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -35,9 +35,12 @@ import android.app.INotificationManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.PendingIntent; +import android.app.Person; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.os.Binder; @@ -118,6 +121,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { assertEquals(canBubble(i), ranking.canBubble()); assertEquals(visuallyInterruptive(i), ranking.visuallyInterruptive()); assertEquals(isConversation(i), ranking.isConversation()); + assertEquals(getShortcutInfo(i).getId(), ranking.getShortcutInfo().getId()); } } @@ -186,7 +190,8 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { (ArrayList) tweak.getSmartReplies(), tweak.canBubble(), tweak.visuallyInterruptive(), - tweak.isConversation() + tweak.isConversation(), + tweak.getShortcutInfo() ); assertNotEquals(nru, nru2); } @@ -264,7 +269,8 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { getSmartReplies(key, i), canBubble(i), visuallyInterruptive(i), - isConversation(i) + isConversation(i), + getShortcutInfo(i) ); rankings[i] = ranking; } @@ -377,6 +383,17 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { return index % 4 == 0; } + private ShortcutInfo getShortcutInfo(int index) { + ShortcutInfo si = new ShortcutInfo( + index, String.valueOf(index), "packageName", new ComponentName("1", "1"), null, + "title", 0, "titleResName", "text", 0, "textResName", + "disabledMessage", 0, "disabledMessageResName", + null, null, 0, null, 0, 0, + 0, "iconResName", "bitmapPath", 0, + null, null); + return si; + } + private void assertActionsEqual( List<Notification.Action> expecteds, List<Notification.Action> actuals) { assertEquals(expecteds.size(), actuals.size()); @@ -411,6 +428,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { assertEquals(comment, a.getSmartReplies(), b.getSmartReplies()); assertEquals(comment, a.canBubble(), b.canBubble()); assertEquals(comment, a.isConversation(), b.isConversation()); + assertEquals(comment, a.getShortcutInfo().getId(), b.getShortcutInfo().getId()); assertActionsEqual(a.getSmartActions(), b.getSmartActions()); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index d0283f78338d..b6cdbfb42c2d 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -153,7 +153,6 @@ import android.widget.RemoteViews; import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; -import com.android.internal.R; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.InstanceIdSequenceFake; @@ -360,7 +359,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Before public void setUp() throws Exception { // Shell permisssions will override permissions of our app, so add all necessary permissions - // fo this test here: + // for this test here: InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( "android.permission.WRITE_DEVICE_CONFIG", "android.permission.READ_DEVICE_CONFIG", @@ -1164,7 +1163,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(PKG, call.r.getSbn().getPackageName()); assertEquals(0, call.r.getSbn().getId()); assertEquals(tag, call.r.getSbn().getTag()); - assertEquals(0, call.getInstanceId()); // Fake instance IDs are assigned in order + assertEquals(1, call.getInstanceId()); // Fake instance IDs are assigned in order } @Test @@ -1186,14 +1185,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals( NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED, mNotificationRecordLogger.get(0).event); - assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId()); + assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); assertTrue(mNotificationRecordLogger.get(1).shouldLogReported); assertEquals( NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED, mNotificationRecordLogger.get(1).event); // Instance ID doesn't change on update of an active notification - assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId()); + assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); } @Test @@ -1248,19 +1247,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED, mNotificationRecordLogger.get(0).event); assertTrue(mNotificationRecordLogger.get(0).shouldLogReported); - assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId()); + assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); assertEquals( NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL, mNotificationRecordLogger.get(1).event); - assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId()); + assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); assertEquals( NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED, mNotificationRecordLogger.get(2).event); assertTrue(mNotificationRecordLogger.get(2).shouldLogReported); // New instance ID because notification was canceled before re-post - assertEquals(1, mNotificationRecordLogger.get(2).getInstanceId()); + assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId()); } @Test @@ -3453,6 +3452,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testStats_dismissalSurface() throws Exception { final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); + r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); mService.addNotification(r); final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); @@ -3470,7 +3470,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals( NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD, mNotificationRecordLogger.get(0).event); - assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId()); + assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); } @Test @@ -4344,6 +4344,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { final NotificationRecord r = generateNotificationRecord( mTestNotificationChannel, 1, null, true); r.setTextChanged(true); + r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); mService.addNotification(r); mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[] @@ -4353,7 +4354,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(1, mNotificationRecordLogger.getCalls().size()); assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN, mNotificationRecordLogger.get(0).event); - assertEquals(0, mNotificationRecordLogger.get(0).getInstanceId()); + assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); mService.mNotificationDelegate.onNotificationVisibilityChanged( new NotificationVisibility[]{}, @@ -4364,7 +4365,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(2, mNotificationRecordLogger.getCalls().size()); assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE, mNotificationRecordLogger.get(1).event); - assertEquals(0, mNotificationRecordLogger.get(1).getInstanceId()); + assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); } @Test @@ -6089,7 +6090,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Pretend the shortcut exists List<ShortcutInfo> shortcutInfos = new ArrayList<>(); - shortcutInfos.add(mock(ShortcutInfo.class)); + ShortcutInfo info = mock(ShortcutInfo.class); + when(info.isLongLived()).thenReturn(true); + shortcutInfos.add(info); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); // Test: Send the bubble notification @@ -6116,7 +6119,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); // We're no longer a bubble - Notification notif2 = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); + Notification notif2 = mService.getNotificationRecord( + nr.getSbn().getKey()).getNotification(); assertFalse(notif2.isBubbleNotification()); } @@ -6409,11 +6413,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { convos.add(convo2); when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); - // only one valid shortcut - LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() - .setPackage(PKG_P) - .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) - .setShortcutIds(Arrays.asList(channel1.getConversationId())); ShortcutInfo si = mock(ShortcutInfo.class); when(si.getShortLabel()).thenReturn("Hello"); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index 2d4b5a73bea0..00b9273c1eb1 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -51,6 +51,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ShortcutInfo; import android.graphics.Color; import android.graphics.drawable.Icon; import android.media.AudioAttributes; @@ -203,16 +204,13 @@ public class NotificationRecordTest extends UiServiceTestCase { return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); } - private StatusBarNotification getMessagingStyleNotification(@Nullable String shortcutId) { + private StatusBarNotification getMessagingStyleNotification() { final Builder builder = new Builder(mMockContext) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon); Person person = new Person.Builder().setName("Bob").build(); builder.setStyle(new Notification.MessagingStyle(person)); - if (shortcutId != null) { - builder.setShortcutId(shortcutId); - } Notification n = builder.build(); return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); @@ -1122,16 +1120,18 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test public void testIsConversation() { - StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); + StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.setShortcutInfo(mock(ShortcutInfo.class)); assertTrue(record.isConversation()); } @Test - public void testIsConversation_nullShortcutId() { - StatusBarNotification sbn = getMessagingStyleNotification(null); + public void testIsConversation_nullShortcut() { + StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.setShortcutInfo(null); assertFalse(record.isConversation()); } @@ -1140,25 +1140,28 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testIsConversation_bypassShortcutFlagEnabled() { Settings.Global.putString(mContentResolver, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true"); - StatusBarNotification sbn = getMessagingStyleNotification(null); + StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.setShortcutInfo(null); assertTrue(record.isConversation()); } @Test public void testIsConversation_channelDemoted() { - StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); + StatusBarNotification sbn = getMessagingStyleNotification(); channel.setDemoted(true); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.setShortcutInfo(mock(ShortcutInfo.class)); assertFalse(record.isConversation()); } @Test public void testIsConversation_withAdjustmentOverride() { - StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); + StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + record.setShortcutInfo(mock(ShortcutInfo.class)); Bundle bundle = new Bundle(); bundle.putBoolean(KEY_NOT_CONVERSATION, true); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index 27f72a13dc60..e4d50c0e1786 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -55,6 +55,8 @@ import android.util.ArraySet; import android.util.AtomicFile; import android.util.Pair; +import androidx.test.InstrumentationRegistry; + import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.InstanceIdSequenceFake; import com.android.server.LocalServices; @@ -65,6 +67,7 @@ import com.android.server.notification.NotificationManagerService.NotificationLi import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.WindowManagerInternal; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -116,6 +119,10 @@ public class RoleObserverTest extends UiServiceTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + // Shell permisssions will override permissions of our app, so add all necessary permissions + // for this test here: + InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( + "android.permission.READ_CONTACTS"); LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class)); @@ -153,6 +160,12 @@ public class RoleObserverTest extends UiServiceTestCase { mService.setPreferencesHelper(mPreferencesHelper); } + @After + public void tearDown() { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation().dropShellPermissionIdentity(); + } + @Test public void testInit() throws Exception { List<String> dialer0 = new ArrayList<>(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 816e8e57acc6..3deeea2d4577 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -22,6 +22,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; @@ -249,7 +250,7 @@ public class SnoozeHelperTest extends UiServiceTestCase { ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class); verify(mAm, times(1)).setExactAndAllowWhileIdle( anyInt(), captor.capture(), any(PendingIntent.class)); - long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime(); + long actualSnoozedUntilDuration = captor.getValue() - System.currentTimeMillis(); assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 250); assertTrue(mSnoozeHelper.isSnoozed( UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), r.getKey())); @@ -363,8 +364,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), "one", 1); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r, false); } @Test @@ -374,8 +375,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL); mSnoozeHelper.snooze(r2, 1000); reset(mAm); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class); verify(mAm).cancel(captor.capture()); assertEquals(r.getKey(), captor.getValue().getIntent().getStringExtra(EXTRA_KEY)); @@ -388,8 +389,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL); mSnoozeHelper.snooze(r2, 1000); reset(mAm); - mSnoozeHelper.repost(r.getKey()); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); verify(mAm).cancel(any(PendingIntent.class)); } @@ -400,10 +401,10 @@ public class SnoozeHelperTest extends UiServiceTestCase { r.getNotification().category = "NEW CATEGORY"; mSnoozeHelper.update(UserHandle.USER_SYSTEM, r); - verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class)); + verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class), anyBoolean()); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); } @Test @@ -420,13 +421,23 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.update(UserHandle.USER_SYSTEM, r); // verify callback is called when repost (snooze is expired) - verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class)); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class), anyBoolean()); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); assertFalse(r.isCanceled); } @Test + public void testReport_passesFlag() throws Exception { + // snooze a notification + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r , 1000); + + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, true); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, true); + } + + @Test public void testGetSnoozedBy() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM); @@ -523,7 +534,7 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.snooze(r2, 1000); mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, "group1"); - verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r); + verify(mCallback, never()).repost(eq(UserHandle.USER_SYSTEM), eq(r), anyBoolean()); } @Test @@ -542,8 +553,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey()); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); - verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r2); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); + verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r2, false); assertEquals(1, mSnoozeHelper.getSnoozed().size()); assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 7204a811fbe2..e1ce431fc97c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -255,7 +255,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { } private void notifyTransitionStarting(ActivityRecord activity) { - final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>(); + final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>(); reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN); mActivityMetricsLogger.notifyTransitionStarting(reasons); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java index 8c2b2939e540..4cb50c7a9e4d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java @@ -103,12 +103,12 @@ public class AppChangeTransitionTests extends WindowTestsBase { setUpOnDisplay(mDisplayContent); mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertEquals(1, mDisplayContent.mChangingApps.size()); + assertEquals(1, mDisplayContent.mChangingContainers.size()); // Verify we are in a change transition, but without a snapshot. // Though, the test will actually have crashed by now if a snapshot is attempted. - assertNull(mActivity.getThumbnail()); - assertTrue(mActivity.isInChangeTransition()); + assertNull(mTask.mSurfaceFreezer.mSnapshot); + assertTrue(mTask.isInChangeTransition()); waitUntilHandlersIdle(); mActivity.removeImmediately(); @@ -121,14 +121,14 @@ public class AppChangeTransitionTests extends WindowTestsBase { setUpOnDisplay(mDisplayContent); mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertEquals(1, mDisplayContent.mChangingApps.size()); - assertTrue(mActivity.isInChangeTransition()); + assertEquals(1, mDisplayContent.mChangingContainers.size()); + assertTrue(mTask.isInChangeTransition()); // Removing the app-token from the display should clean-up the // the change leash. mDisplayContent.removeAppToken(mActivity.token); - assertEquals(0, mDisplayContent.mChangingApps.size()); - assertFalse(mActivity.isInChangeTransition()); + assertEquals(0, mDisplayContent.mChangingContainers.size()); + assertFalse(mTask.isInChangeTransition()); waitUntilHandlersIdle(); mActivity.removeImmediately(); @@ -152,8 +152,8 @@ public class AppChangeTransitionTests extends WindowTestsBase { assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode()); // Make sure we're not waiting for a change animation (no leash) - assertFalse(mActivity.isInChangeTransition()); - assertNull(mActivity.getThumbnail()); + assertFalse(mTask.isInChangeTransition()); + assertNull(mActivity.mSurfaceFreezer.mSnapshot); waitUntilHandlersIdle(); mActivity.removeImmediately(); @@ -165,13 +165,13 @@ public class AppChangeTransitionTests extends WindowTestsBase { setUpOnDisplay(mDisplayContent); mTask.setWindowingMode(WINDOWING_MODE_FREEFORM); - assertEquals(1, mDisplayContent.mChangingApps.size()); - assertTrue(mActivity.isInChangeTransition()); + assertEquals(1, mDisplayContent.mChangingContainers.size()); + assertTrue(mTask.isInChangeTransition()); // Changing visibility should cancel the change transition and become closing mActivity.setVisibility(false, false); - assertEquals(0, mDisplayContent.mChangingApps.size()); - assertFalse(mActivity.isInChangeTransition()); + assertEquals(0, mDisplayContent.mChangingContainers.size()); + assertFalse(mTask.isInChangeTransition()); waitUntilHandlersIdle(); mActivity.removeImmediately(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 2b0ad890aae1..e2c27ea55b13 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -50,6 +50,7 @@ import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; +import android.app.WindowConfiguration; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -268,6 +269,26 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); } + @Test + public void layoutWindowLw_fitDisplayCutout() { + assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL); + addDisplayCutout(); + + mWindow.mAttrs.setFitInsetsTypes(Type.displayCutout()); + mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + addWindow(mWindow); + + mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); + mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames); + + assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0); + assertInsetByTopBottom(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0); + assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT); + assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0); + } + // TODO(b/118118435): remove after migration @Test public void layoutWindowLw_appDrawsBarsLegacy() { @@ -855,9 +876,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { final DisplayCutout.ParcelableWrapper outDisplayCutout = new DisplayCutout.ParcelableWrapper(); - mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, null, mFrames, - false /* floatingStack */, outFrame, outContentInsets, outStableInsets, - outDisplayCutout); + mDisplayPolicy.getLayoutHint(mWindow.mAttrs, null /* windowToken */, outFrame, + outContentInsets, outStableInsets, outDisplayCutout); assertThat(outFrame, is(mFrames.mUnrestricted)); assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT))); @@ -874,6 +894,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); final Rect taskBounds = new Rect(100, 100, 200, 200); + final Task task = mWindow.getTask(); + // Force the bounds because the task may resolve different bounds from Task#setBounds. + task.getWindowConfiguration().setBounds(taskBounds); final Rect outFrame = new Rect(); final Rect outContentInsets = new Rect(); @@ -881,9 +904,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { final DisplayCutout.ParcelableWrapper outDisplayCutout = new DisplayCutout.ParcelableWrapper(); - mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames, - false /* floatingStack */, outFrame, outContentInsets, outStableInsets, - outDisplayCutout); + mDisplayPolicy.getLayoutHint(mWindow.mAttrs, mWindow.mToken, outFrame, + outContentInsets, outStableInsets, outDisplayCutout); assertThat(outFrame, is(taskBounds)); assertThat(outContentInsets, is(new Rect())); @@ -904,15 +926,20 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { final Rect taskBounds = new Rect(100, mFrames.mContent.bottom + 1, 200, mFrames.mContent.bottom + 10); + final Task task = mWindow.getTask(); + // Make the task floating. + task.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM); + // Force the bounds because the task may resolve different bounds from Task#setBounds. + task.getWindowConfiguration().setBounds(taskBounds); + final Rect outFrame = new Rect(); final Rect outContentInsets = new Rect(); final Rect outStableInsets = new Rect(); final DisplayCutout.ParcelableWrapper outDisplayCutout = new DisplayCutout.ParcelableWrapper(); - mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames, - true /* floatingStack */, outFrame, outContentInsets, outStableInsets, - outDisplayCutout); + mDisplayPolicy.getLayoutHint(mWindow.mAttrs, mWindow.mToken, outFrame, outContentInsets, + outStableInsets, outDisplayCutout); assertThat(outFrame, is(taskBounds)); assertThat(outContentInsets, is(new Rect())); @@ -939,6 +966,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { final InsetsState simulatedInsetsState = new InsetsState(); final DisplayFrames simulatedDisplayFrames = createDisplayFrames(); mDisplayPolicy.beginLayoutLw(mFrames, uiMode); + // Force the display bounds because it is not synced with display frames in policy test. + mDisplayContent.getWindowConfiguration().setBounds(mFrames.mUnrestricted); mDisplayContent.getInsetsStateController().onPostLayout(); mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState, uiMode); @@ -947,20 +976,18 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { final StringWriter simulatedFramesDump = new StringWriter(); simulatedDisplayFrames.dump(prefix, new PrintWriter(simulatedFramesDump)); - assertEquals(realFramesDump.toString(), simulatedFramesDump.toString()); + assertEquals(new ToStringComparatorWrapper<>(realFramesDump), + new ToStringComparatorWrapper<>(simulatedFramesDump)); - final StringWriter realInsetsDump = new StringWriter(); final InsetsState realInsetsState = new InsetsState( mDisplayContent.getInsetsStateController().getRawInsetsState()); // Exclude comparing IME insets because currently the simulated layout only focuses on the // insets from status bar and navigation bar. realInsetsState.removeSource(InsetsState.ITYPE_IME); realInsetsState.removeSource(InsetsState.ITYPE_CAPTION_BAR); - realInsetsState.dump(prefix, new PrintWriter(realInsetsDump)); - final StringWriter simulatedInsetsDump = new StringWriter(); - simulatedInsetsState.dump(prefix, new PrintWriter(simulatedInsetsDump)); - assertEquals(realInsetsDump.toString(), simulatedInsetsDump.toString()); + assertEquals(new ToStringComparatorWrapper<>(realInsetsState), + new ToStringComparatorWrapper<>(simulatedInsetsState)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DockedStackDividerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DockedStackDividerControllerTests.java deleted file mode 100644 index 32062080a22c..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/DockedStackDividerControllerTests.java +++ /dev/null @@ -1,88 +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.wm; - -import static android.view.WindowManager.DOCKED_BOTTOM; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_RIGHT; -import static android.view.WindowManager.DOCKED_TOP; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; - -@SmallTest -@Presubmit -public class DockedStackDividerControllerTests { - - @Test - public void testIsDockSideAllowedDockTop() { - // Docked top is always allowed - assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, - NAV_BAR_BOTTOM, true /* navigationBarCanMove */)); - assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, - NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); - } - - @Test - public void testIsDockSideAllowedDockBottom() { - // Cannot dock bottom - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT, - NAV_BAR_BOTTOM, true /* navigationBarCanMove */)); - } - - @Test - public void testIsDockSideAllowedNavigationBarMovable() { - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, - NAV_BAR_BOTTOM, true /* navigationBarCanMove */)); - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, - NAV_BAR_LEFT, true /* navigationBarCanMove */)); - assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, - NAV_BAR_RIGHT, true /* navigationBarCanMove */)); - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, - NAV_BAR_BOTTOM, true /* navigationBarCanMove */)); - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, - NAV_BAR_RIGHT, true /* navigationBarCanMove */)); - assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, - NAV_BAR_LEFT, true /* navigationBarCanMove */)); - } - - @Test - public void testIsDockSideAllowedNavigationBarNotMovable() { - // Navigation bar is not movable such as tablets - assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, - NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); - assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_TOP, - NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_RIGHT, - NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, - NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); - assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_TOP, - NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); - assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_RIGHT, - NAV_BAR_BOTTOM, false /* navigationBarCanMove */)); - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index d9c5c4c7dffc..9a898fda4ef3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -17,7 +17,6 @@ package com.android.server.wm; import static android.app.ActivityManager.RECENT_WITH_EXCLUDED; -import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; @@ -978,10 +977,7 @@ public class RecentTasksTest extends ActivityTestsBase { () -> mService.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN, false/* toTop */)); assertNotRestoreTask( - () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId, - SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, - false /* toTop */, false /* animate */, null /* initialBounds */, - true /* showRecents */)); + () -> mService.setTaskWindowingModeSplitScreenPrimary(taskId, false /* toTop */)); } @Test @@ -1096,14 +1092,10 @@ public class RecentTasksTest extends ActivityTestsBase { assertSecurityException(expectCallable, () -> mService.moveTaskToStack(0, INVALID_STACK_ID, true)); assertSecurityException(expectCallable, - () -> mService.setTaskWindowingModeSplitScreenPrimary(0, - SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT, true, true, new Rect(), true)); + () -> mService.setTaskWindowingModeSplitScreenPrimary(0, true)); assertSecurityException(expectCallable, () -> mService.dismissPip(true, 0)); assertSecurityException(expectCallable, () -> mService.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect())); - assertSecurityException(expectCallable, - () -> mService.resizeDockedStack(new Rect(), new Rect(), new Rect(), new Rect(), - new Rect())); assertSecurityException(expectCallable, () -> mService.getAllStackInfos()); assertSecurityException(expectCallable, () -> mService.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED)); diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index 3a724a140ffb..c7f94efdfde0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -247,7 +247,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { @Test public void testChange() throws Exception { final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin"); - mDisplayContent.mChangingApps.add(win.mActivityRecord); + mDisplayContent.mChangingContainers.add(win.mActivityRecord); try { final RemoteAnimationRecord record = mController.createRemoteAnimationRecord( win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), @@ -290,7 +290,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase { verify(mThumbnailFinishedCallback).onAnimationFinished( eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter)); } finally { - mDisplayContent.mChangingApps.clear(); + mDisplayContent.mChangingContainers.clear(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index ec2026255f8e..0ef25824df2a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -52,7 +52,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.refEq; import android.app.ActivityOptions; -import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -251,13 +250,12 @@ public class RootActivityContainerTests extends ActivityTestsBase { final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true) .setStack(stack).build(); - // Under split screen primary we should be focusable when not minimized - mRootWindowContainer.setDockedStackMinimized(false); + // Created stacks are focusable by default. assertTrue(stack.isTopActivityFocusable()); assertTrue(activity.isFocusable()); - // Under split screen primary we should not be focusable when minimized - mRootWindowContainer.setDockedStackMinimized(true); + // If the stack is made unfocusable, its activities should inherit that. + stack.setFocusable(false); assertFalse(stack.isTopActivityFocusable()); assertFalse(activity.isFocusable()); @@ -308,33 +306,6 @@ public class RootActivityContainerTests extends ActivityTestsBase { } /** - * Verify split-screen primary stack & task can resized by - * {@link android.app.IActivityTaskManager#resizeDockedStack} as expect. - */ - @Test - public void testResizeDockedStackForSplitScreenPrimary() { - final Rect configSize = new Rect(0, 0, 1000, 1000); - final Rect displayedSize = new Rect(0, 0, 300, 300); - - // Create primary split-screen stack with a task. - final ActivityStack primaryStack = new StackBuilder(mRootWindowContainer) - .setActivityType(ACTIVITY_TYPE_STANDARD) - .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) - .setOnTop(true) - .build(); - final Task task = primaryStack.getTopMostTask(); - - // Resize dock stack. - mService.resizeDockedStack(displayedSize, configSize, null, null, null); - - // Verify dock stack & its task bounds if is equal as resized result. - assertEquals(displayedSize, primaryStack.getDisplayedBounds()); - assertEquals(displayedSize, primaryStack.getDisplayedBounds()); - assertEquals(configSize, primaryStack.getBounds()); - assertEquals(configSize, task.getBounds()); - } - - /** * Verify that home stack would be moved to front when the top activity is Recents. */ @Test @@ -517,7 +488,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { */ @Test public void testStartHomeOnAllDisplays() { - mockResolveHomeActivity(); + mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); mockResolveSecondaryHomeActivity(); // Create secondary displays. @@ -644,30 +615,26 @@ public class RootActivityContainerTests extends ActivityTestsBase { } /** - * Tests that secondary home should be selected if default home not set. + * Tests that secondary home should be selected if primary home not set. */ @Test - public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSet() { - final Intent defaultHomeIntent = mService.getHomeIntent(); - final ActivityInfo aInfoDefault = new ActivityInfo(); - aInfoDefault.name = ResolverActivity.class.getName(); - doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(), - refEq(defaultHomeIntent)); - - final String secondaryHomeComponent = mService.mContext.getResources().getString( - com.android.internal.R.string.config_secondaryHomeComponent); - final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent); - final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null); - final ActivityInfo aInfoSecondary = new ActivityInfo(); - aInfoSecondary.name = comp.getClassName(); - doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(), - refEq(secondaryHomeIntent)); - - // Should fallback to secondary home if default home not set. + public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() { + // Setup: primary home not set. + final Intent primaryHomeIntent = mService.getHomeIntent(); + final ActivityInfo aInfoPrimary = new ActivityInfo(); + aInfoPrimary.name = ResolverActivity.class.getName(); + doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(), + refEq(primaryHomeIntent)); + // Setup: set secondary home. + mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */); + + // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); - - assertEquals(comp.getClassName(), resolvedInfo.first.name); + final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); + assertEquals(aInfoSecondary.name, resolvedInfo.first.name); + assertEquals(aInfoSecondary.applicationInfo.packageName, + resolvedInfo.first.applicationInfo.packageName); } /** @@ -675,103 +642,60 @@ public class RootActivityContainerTests extends ActivityTestsBase { * config_useSystemProvidedLauncherForSecondary. */ @Test - public void testResolveSecondaryHomeActivityForced() throws Exception { - Resources resources = mContext.getResources(); - spyOn(resources); - try { - // setUp: set secondary launcher and force it. - final String defaultSecondaryHome = - "com.android.test/com.android.test.TestDefaultSecondaryHome"; - final ComponentName secondaryComp = ComponentName.unflattenFromString( - defaultSecondaryHome); - doReturn(defaultSecondaryHome).when(resources).getString( - com.android.internal.R.string.config_secondaryHomeComponent); - doReturn(true).when(resources).getBoolean( - com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary); - final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null); - assertEquals(secondaryComp, secondaryHomeIntent.getComponent()); - final ActivityInfo aInfoSecondary = new ActivityInfo(); - aInfoSecondary.name = secondaryComp.getClassName(); - aInfoSecondary.applicationInfo = new ApplicationInfo(); - aInfoSecondary.applicationInfo.packageName = secondaryComp.getPackageName(); - doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(), - refEq(secondaryHomeIntent)); - final Intent homeIntent = mService.getHomeIntent(); - final ActivityInfo aInfoDefault = new ActivityInfo(); - aInfoDefault.name = "fakeHomeActivity"; - aInfoDefault.applicationInfo = new ApplicationInfo(); - aInfoDefault.applicationInfo.packageName = "fakeHomePackage"; - doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(), - refEq(homeIntent)); - // Let resolveActivities call to validate both main launcher and second launcher so that - // resolveActivities call does not work as enabler for secondary. - final List<ResolveInfo> resolutions1 = new ArrayList<>(); - final ResolveInfo resolveInfo1 = new ResolveInfo(); - resolveInfo1.activityInfo = new ActivityInfo(); - resolveInfo1.activityInfo.name = aInfoDefault.name; - resolveInfo1.activityInfo.applicationInfo = aInfoDefault.applicationInfo; - resolutions1.add(resolveInfo1); - doReturn(resolutions1).when(mRootWindowContainer).resolveActivities(anyInt(), - refEq(homeIntent)); - final List<ResolveInfo> resolutions2 = new ArrayList<>(); - final ResolveInfo resolveInfo2 = new ResolveInfo(); - resolveInfo2.activityInfo = new ActivityInfo(); - resolveInfo2.activityInfo.name = aInfoSecondary.name; - resolveInfo2.activityInfo.applicationInfo = aInfoSecondary.applicationInfo; - resolutions2.add(resolveInfo2); - doReturn(resolutions2).when(mRootWindowContainer).resolveActivities(anyInt(), - refEq(secondaryHomeIntent)); - doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay( - any(), anyInt(), anyBoolean()); - - // Run the test - final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); - assertEquals(secondaryComp.getClassName(), resolvedInfo.first.name); - assertEquals(secondaryComp.getPackageName(), - resolvedInfo.first.applicationInfo.packageName); - assertEquals(aInfoSecondary.name, resolvedInfo.first.name); - } finally { - // tearDown - reset(resources); - } + public void testResolveSecondaryHomeActivityForced() { + // SetUp: set primary home. + mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); + // SetUp: set secondary home and force it. + mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */); + final Intent secondaryHomeIntent = + mService.getSecondaryHomeIntent(null /* preferredPackage */); + final List<ResolveInfo> resolutions = new ArrayList<>(); + final ResolveInfo resolveInfo = new ResolveInfo(); + final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); + resolveInfo.activityInfo = aInfoSecondary; + resolutions.add(resolveInfo); + doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), + refEq(secondaryHomeIntent)); + doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay( + any(), anyInt(), anyBoolean()); + + // Run the test. + final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer + .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + assertEquals(aInfoSecondary.name, resolvedInfo.first.name); + assertEquals(aInfoSecondary.applicationInfo.packageName, + resolvedInfo.first.applicationInfo.packageName); } /** - * Tests that secondary home should be selected if default home not support secondary displays - * or there is no matched activity in the same package as selected default home. + * Tests that secondary home should be selected if primary home not support secondary displays + * or there is no matched activity in the same package as selected primary home. */ @Test - public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSupportMultiDisplay() { - mockResolveHomeActivity(); - + public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay() { + // Setup: there is no matched activity in the same package as selected primary home. + mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); final List<ResolveInfo> resolutions = new ArrayList<>(); doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any()); + // Setup: set secondary home. + mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */); - final String secondaryHomeComponent = mService.mContext.getResources().getString( - com.android.internal.R.string.config_secondaryHomeComponent); - final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent); - final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null); - final ActivityInfo aInfoSecondary = new ActivityInfo(); - aInfoSecondary.name = comp.getClassName(); - doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(), - refEq(secondaryHomeIntent)); - - // Should fallback to secondary home if selected default home not support secondary displays - // or there is no matched activity in the same package as selected default home. + // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); - - assertEquals(comp.getClassName(), resolvedInfo.first.name); + final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); + assertEquals(aInfoSecondary.name, resolvedInfo.first.name); + assertEquals(aInfoSecondary.applicationInfo.packageName, + resolvedInfo.first.applicationInfo.packageName); } - /** - * Tests that default home activity should be selected if it already support secondary displays. + * Tests that primary home activity should be selected if it already support secondary displays. */ @Test - public void testResolveSecondaryHomeActivityWhenDefaultHomeSupportMultiDisplay() { - final ActivityInfo aInfoDefault = mockResolveHomeActivity(); - + public void testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay() { + // SetUp: set primary home. + mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); + // SetUp: put primary home info on 2nd item final List<ResolveInfo> resolutions = new ArrayList<>(); final ResolveInfo infoFake1 = new ResolveInfo(); infoFake1.activityInfo = new ActivityInfo(); @@ -779,7 +703,8 @@ public class RootActivityContainerTests extends ActivityTestsBase { infoFake1.activityInfo.applicationInfo = new ApplicationInfo(); infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1"; final ResolveInfo infoFake2 = new ResolveInfo(); - infoFake2.activityInfo = aInfoDefault; + final ActivityInfo aInfoPrimary = getFakeHomeActivityInfo(true /* primaryHome */); + infoFake2.activityInfo = aInfoPrimary; resolutions.add(infoFake1); resolutions.add(infoFake2); doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any()); @@ -787,13 +712,12 @@ public class RootActivityContainerTests extends ActivityTestsBase { doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay( any(), anyInt(), anyBoolean()); - // Use default home activity if it support secondary displays. + // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); - - assertEquals(aInfoDefault.applicationInfo.packageName, + assertEquals(aInfoPrimary.name, resolvedInfo.first.name); + assertEquals(aInfoPrimary.applicationInfo.packageName, resolvedInfo.first.applicationInfo.packageName); - assertEquals(aInfoDefault.name, resolvedInfo.first.name); } /** @@ -801,8 +725,9 @@ public class RootActivityContainerTests extends ActivityTestsBase { */ @Test public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() { - mockResolveHomeActivity(); - + // SetUp: set primary home. + mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */); + // Setup: prepare two eligible activity info. final List<ResolveInfo> resolutions = new ArrayList<>(); final ResolveInfo infoFake1 = new ResolveInfo(); infoFake1.activityInfo = new ActivityInfo(); @@ -821,7 +746,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay( any(), anyInt(), anyBoolean()); - // Use the first one of matched activities in the same package as selected default home. + // Use the first one of matched activities in the same package as selected primary home. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); @@ -884,32 +809,48 @@ public class RootActivityContainerTests extends ActivityTestsBase { /** * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity - * info for test cases (the original implementation will resolve from the real package manager). + * info for test cases. + * + * @param primaryHome Indicate to use primary home intent as parameter, otherwise, use + * secondary home intent. + * @param forceSystemProvided Indicate to force using system provided home activity. */ - private ActivityInfo mockResolveHomeActivity() { - final Intent homeIntent = mService.getHomeIntent(); - final ActivityInfo aInfoDefault = new ActivityInfo(); - aInfoDefault.name = "fakeHomeActivity"; - aInfoDefault.applicationInfo = new ApplicationInfo(); - aInfoDefault.applicationInfo.packageName = "fakeHomePackage"; - doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(), - refEq(homeIntent)); - return aInfoDefault; + private void mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided) { + ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome); + Intent targetIntent; + if (primaryHome) { + targetIntent = mService.getHomeIntent(); + } else { + Resources resources = mContext.getResources(); + spyOn(resources); + doReturn(targetActivityInfo.applicationInfo.packageName).when(resources).getString( + com.android.internal.R.string.config_secondaryHomePackage); + doReturn(forceSystemProvided).when(resources).getBoolean( + com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary); + targetIntent = mService.getSecondaryHomeIntent(null /* preferredPackage */); + } + doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(), + refEq(targetIntent)); } /** * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent - * activity info for test cases (the original implementation will resolve from the real package - * manager). + * activity info for test cases. */ private void mockResolveSecondaryHomeActivity() { final Intent secondaryHomeIntent = mService .getSecondaryHomeIntent(null /* preferredPackage */); - final ActivityInfo aInfoSecondary = new ActivityInfo(); - aInfoSecondary.name = "fakeSecondaryHomeActivity"; - aInfoSecondary.applicationInfo = new ApplicationInfo(); - aInfoSecondary.applicationInfo.packageName = "fakeSecondaryHomePackage"; + final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false); doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer) .resolveSecondaryHomeActivity(anyInt(), anyInt()); } + + private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) { + final ActivityInfo aInfo = new ActivityInfo(); + aInfo.name = primaryHome ? "fakeHomeActivity" : "fakeSecondaryHomeActivity"; + aInfo.applicationInfo = new ApplicationInfo(); + aInfo.applicationInfo.packageName = + primaryHome ? "fakeHomePackage" : "fakeSecondaryHomePackage"; + return aInfo; + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java index 7e31895aa991..f6ed31455f18 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java @@ -60,4 +60,26 @@ class SystemServiceTestsBase { <T> T awaitInWmLock(Callable<T> callable) { return mLockRule.waitForLocked(callable); } + + /** + * Utility class to compare the output of T#toString. It is convenient to have readable output + * of assertion if the string content can represent the expected states. + */ + static class ToStringComparatorWrapper<T> { + final T mObject; + + ToStringComparatorWrapper(T object) { + mObject = object; + } + + @Override + public boolean equals(Object obj) { + return mObject.toString().equals(obj.toString()); + } + + @Override + public String toString() { + return mObject.toString(); + } + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java index bd8aacb6cb96..20d9aff5f3bf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java @@ -25,6 +25,7 @@ import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_APP_THE import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @@ -36,6 +37,7 @@ import android.content.res.Configuration; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; @@ -138,6 +140,7 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { final int orientation = Configuration.ORIENTATION_PORTRAIT; final float scaleFraction = 0.25f; final Rect contentInsets = new Rect(1, 2, 3, 4); + final Point taskSize = new Point(5, 6); try { ActivityManager.TaskSnapshot.Builder builder = @@ -147,14 +150,13 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { builder.setSystemUiVisibility(systemUiVisibility); builder.setWindowingMode(windowingMode); builder.setColorSpace(sRGB); - builder.setIsLowResolution(true); builder.setOrientation(orientation); builder.setContentInsets(contentInsets); builder.setIsTranslucent(true); - builder.setScaleFraction(0.25f); builder.setSnapshot(buffer); builder.setIsRealSnapshot(true); builder.setPixelFormat(pixelFormat); + builder.setTaskSize(taskSize); // Not part of TaskSnapshot itself, used in screenshot process assertEquals(pixelFormat, builder.getPixelFormat()); @@ -165,13 +167,15 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { assertEquals(systemUiVisibility, snapshot.getSystemUiVisibility()); assertEquals(windowingMode, snapshot.getWindowingMode()); assertEquals(sRGB, snapshot.getColorSpace()); - assertTrue(snapshot.isLowResolution()); + // Snapshots created with the Builder class are always high-res. The only way to get a + // low-res snapshot is to load it from the disk in TaskSnapshotLoader. + assertFalse(snapshot.isLowResolution()); assertEquals(orientation, snapshot.getOrientation()); assertEquals(contentInsets, snapshot.getContentInsets()); assertTrue(snapshot.isTranslucent()); - assertEquals(scaleFraction, builder.getScaleFraction(), 0.001f); assertSame(buffer, snapshot.getSnapshot()); assertTrue(snapshot.isRealSnapshot()); + assertEquals(taskSize, snapshot.getTaskSize()); } finally { if (buffer != null) { buffer.destroy(); @@ -188,11 +192,9 @@ public class TaskSnapshotControllerTest extends WindowTestsBase { final ActivityManager.TaskSnapshot.Builder builder = new ActivityManager.TaskSnapshot.Builder(); - final float scaleFraction = 0.8f; mWm.mTaskSnapshotController.prepareTaskSnapshot(mAppWindow.mActivityRecord.getTask(), - scaleFraction, PixelFormat.UNKNOWN, builder); + PixelFormat.UNKNOWN, builder); - assertEquals(scaleFraction, builder.getScaleFraction(), 0 /* delta */); // The pixel format should be selected automatically. assertNotEquals(PixelFormat.UNKNOWN, builder.getPixelFormat()); } 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 0b16e5ce8b97..40f15b7e9d39 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java @@ -19,12 +19,16 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; +import android.app.ActivityManager; import android.app.ActivityManager.TaskSnapshot; import android.content.res.Configuration; import android.graphics.Rect; @@ -36,10 +40,12 @@ import android.view.View; import androidx.test.filters.MediumTest; +import com.android.server.wm.TaskSnapshotLoader.PreRLegacySnapshotConfig; import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoSession; import java.io.File; import java.util.function.Predicate; @@ -55,6 +61,8 @@ import java.util.function.Predicate; @RunWith(WindowTestRunner.class) public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase { + private static final float DELTA = 0.00001f; + private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40); @Test @@ -148,29 +156,172 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa } @Test - public void testLowResolutionPersistAndLoadSnapshot() { + public void testLegacyPLowRamConfig() throws Exception { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .mockStatic(ActivityManager.class) + .startMocking(); + + when(ActivityManager.isLowRamDeviceStatic()).thenReturn(true); + + // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file, + // for any P low_ram device + final int taskWidth = 0; + final float legacyScale = 0f; + final boolean hasHighResFile = false; + + PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */); + assertNotNull(highResConf); + assertEquals(highResConf.mScale, 0.6f, DELTA); + assertTrue(highResConf.mForceLoadReducedJpeg); + + PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */); + assertNotNull(lowResConf); + assertEquals(lowResConf.mScale, 0.6f, DELTA); + assertTrue(lowResConf.mForceLoadReducedJpeg); + + mockSession.finishMocking(); + } + + @Test + public void testLegacyPNonLowRamConfig() throws Exception { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .mockStatic(ActivityManager.class) + .startMocking(); + + when(ActivityManager.isLowRamDeviceStatic()).thenReturn(false); + + // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file, + // for any O device, or a P non-low_ram device + final int taskWidth = 0; + final float legacyScale = 0f; + final boolean hasHighResFile = true; + + PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */); + assertNotNull(highResConf); + assertEquals(highResConf.mScale, 1.0f, DELTA); + assertFalse(highResConf.mForceLoadReducedJpeg); + + PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */); + assertNotNull(lowResConf); + assertEquals(lowResConf.mScale, 0.5f, DELTA); + assertFalse(lowResConf.mForceLoadReducedJpeg); + + mockSession.finishMocking(); + } + + @Test + public void testLegacyQLowRamConfig() throws Exception { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .mockStatic(ActivityManager.class) + .startMocking(); + + when(ActivityManager.isLowRamDeviceStatic()).thenReturn(true); + + // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file, + // for any Q low_ram device + final int taskWidth = 0; + final float legacyScale = 0.6f; + final boolean hasHighResFile = false; + + PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */); + assertNotNull(highResConf); + assertEquals(highResConf.mScale, legacyScale, DELTA); + assertEquals(highResConf.mScale, 0.6f, DELTA); + assertTrue(highResConf.mForceLoadReducedJpeg); + + PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */); + assertNotNull(lowResConf); + assertEquals(lowResConf.mScale, legacyScale, DELTA); + assertEquals(lowResConf.mScale, 0.6f, DELTA); + assertTrue(lowResConf.mForceLoadReducedJpeg); + + mockSession.finishMocking(); + } + + @Test + public void testLegacyQNonLowRamConfig() throws Exception { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .mockStatic(ActivityManager.class) + .startMocking(); + + when(ActivityManager.isLowRamDeviceStatic()).thenReturn(false); + + // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file, + // for any Q non-low_ram device + final int taskWidth = 0; + final float legacyScale = 0.8f; + final boolean hasHighResFile = true; + + PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */); + assertNotNull(highResConf); + assertEquals(highResConf.mScale, legacyScale, DELTA); + assertEquals(highResConf.mScale, 0.8f, DELTA); + assertFalse(highResConf.mForceLoadReducedJpeg); + + PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */); + assertNotNull(lowResConf); + assertEquals(lowResConf.mScale, 0.5f * legacyScale, DELTA); + assertEquals(lowResConf.mScale, 0.5f * 0.8f, DELTA); + assertFalse(lowResConf.mForceLoadReducedJpeg); + + mockSession.finishMocking(); + } + + @Test + public void testNonLegacyRConfig() throws Exception { + // taskWidth and legacyScale as would be defined in the proto, and presence of a *.jpg file, + // for any R device + final int taskWidth = 1440; + final float legacyScale = 0f; + final boolean hasHighResFile = true; + + PreRLegacySnapshotConfig highResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, false /* loadLowResolutionBitmap */); + assertNull(highResConf); + + PreRLegacySnapshotConfig lowResConf = mLoader.getLegacySnapshotConfig( + taskWidth, legacyScale, hasHighResFile, true /* loadLowResolutionBitmap */); + assertNull(lowResConf); + } + + @Test + public void testDisabledLowResolutionPersistAndLoadSnapshot() { + mPersister.setEnableLowResSnapshots(false); + TaskSnapshot a = new TaskSnapshotBuilder() - .setScale(0.5f) + .setScaleFraction(0.5f) .setIsLowResolution(true) .build(); assertTrue(a.isLowResolution()); mPersister.persistSnapshot(1, mTestUserId, a); mPersister.waitForQueueEmpty(); final File[] files = new File[]{new File(FILES_DIR.getPath() + "/snapshots/1.proto"), - new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")}; + new File(FILES_DIR.getPath() + "/snapshots/1.jpg")}; final File[] nonExistsFiles = new File[]{ - new File(FILES_DIR.getPath() + "/snapshots/1.jpg"), + new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"), }; assertTrueForFiles(files, File::exists, " must exist"); assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist"); - final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, true /* isLowResolution */); + final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* isLowResolution */); assertNotNull(snapshot); assertEquals(TEST_INSETS, snapshot.getContentInsets()); assertNotNull(snapshot.getSnapshot()); assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation()); final TaskSnapshot snapshotNotExist = mLoader.loadTask(1, mTestUserId, - false /* isLowResolution */); + true /* isLowResolution */); assertNull(snapshotNotExist); } @@ -271,13 +422,11 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa @Test public void testScalePersistAndLoadSnapshot() { TaskSnapshot a = new TaskSnapshotBuilder() - .setScale(0.25f) + .setScaleFraction(0.25f) .build(); TaskSnapshot b = new TaskSnapshotBuilder() - .setScale(0.75f) + .setScaleFraction(0.75f) .build(); - assertEquals(0.25f, a.getScale(), 1E-5); - assertEquals(0.75f, b.getScale(), 1E-5); mPersister.persistSnapshot(1, mTestUserId, a); mPersister.persistSnapshot(2, mTestUserId, b); mPersister.waitForQueueEmpty(); @@ -287,8 +436,6 @@ public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBa false /* isLowResolution */); assertNotNull(snapshotA); assertNotNull(snapshotB); - assertEquals(0.25f, snapshotA.getScale(), 1E-5); - assertEquals(0.75f, snapshotB.getScale(), 1E-5); } @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 4612dbab0a59..fa6663c06371 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java @@ -30,6 +30,7 @@ import android.graphics.Color; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; import android.os.UserManager; import android.view.Surface; @@ -87,8 +88,10 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { * Builds a TaskSnapshot. */ static class TaskSnapshotBuilder { + private static final int SNAPSHOT_WIDTH = 100; + private static final int SNAPSHOT_HEIGHT = 100; - private float mScale = 1f; + private float mScaleFraction = 1f; private boolean mIsLowResolution = false; private boolean mIsRealSnapshot = true; private boolean mIsTranslucent = false; @@ -96,8 +99,11 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { private int mSystemUiVisibility = 0; private int mRotation = Surface.ROTATION_0; - TaskSnapshotBuilder setScale(float scale) { - mScale = scale; + TaskSnapshotBuilder() { + } + + TaskSnapshotBuilder setScaleFraction(float scale) { + mScaleFraction = scale; return this; } @@ -132,15 +138,20 @@ class TaskSnapshotPersisterTestBase extends WindowTestsBase { } TaskSnapshot build() { - final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888, + // To satisfy existing tests, ensure the graphics buffer is always 100x100, and + // compute the ize of the task according to mScaleFraction. + Point taskSize = new Point((int) (SNAPSHOT_WIDTH / mScaleFraction), + (int) (SNAPSHOT_HEIGHT / mScaleFraction)); + final GraphicBuffer buffer = GraphicBuffer.create(SNAPSHOT_WIDTH, SNAPSHOT_HEIGHT, + PixelFormat.RGBA_8888, USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY); Canvas c = buffer.lockCanvas(); c.drawColor(Color.RED); buffer.unlockCanvasAndPost(c); return new TaskSnapshot(MOCK_SNAPSHOT_ID, new ComponentName("", ""), buffer, ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, - mRotation, TEST_INSETS, - mIsLowResolution, mScale, mIsRealSnapshot, + mRotation, taskSize, TEST_INSETS, + mIsLowResolution, mIsRealSnapshot, mWindowingMode, mSystemUiVisibility, mIsTranslucent); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index bb0e5aec8e2e..2164de9ea191 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -38,6 +38,7 @@ import android.graphics.Color; import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.PixelFormat; +import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.Surface; @@ -67,12 +68,22 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { int windowFlags, Rect taskBounds) { final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888, GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER); + + // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic + // this behavior set the taskSize to be the same as the taskBounds width and height. The + // taskBounds passed here are assumed to be the same task bounds as when the snapshot was + // taken. We assume there is no aspect ratio mismatch between the screenshot and the + // taskBounds + assertEquals(width, taskBounds.width()); + assertEquals(height, taskBounds.height()); + Point taskSize = new Point(taskBounds.width(), taskBounds.height()); + final TaskSnapshot snapshot = new TaskSnapshot( System.currentTimeMillis(), new ComponentName("", ""), buffer, ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, - Surface.ROTATION_0, contentInsets, false, - 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, + Surface.ROTATION_0, taskSize, contentInsets, false, + true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */); mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test", createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0, @@ -152,7 +163,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { @Test public void testCalculateSnapshotCrop_taskNotOnTop() { - setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 100)); + setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150)); assertEquals(new Rect(0, 10, 100, 90), mSurface.calculateSnapshotCrop()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 2c68cc7a19bf..85e4a1668a35 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -251,9 +251,11 @@ public class WindowStateTests extends WindowTestsBase { // b/145812508: special legacy use-case for transparent/translucent windows. appWindow.mAttrs.format = PixelFormat.TRANSPARENT; + appWindow.mAttrs.alpha = 0; assertTrue(appWindow.canBeImeTarget()); appWindow.mAttrs.format = PixelFormat.OPAQUE; + appWindow.mAttrs.alpha = 1; appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM; assertFalse(appWindow.canBeImeTarget()); appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE; @@ -276,8 +278,7 @@ public class WindowStateTests extends WindowTestsBase { spyOn(appWindow); spyOn(controller); spyOn(stack); - doReturn(true).when(controller).isMinimizedDock(); - doReturn(true).when(controller).isHomeStackResizable(); + stack.setFocusable(false); doReturn(stack).when(appWindow).getRootTask(); // Make sure canBeImeTarget is false due to shouldIgnoreInput is true; @@ -619,9 +620,10 @@ public class WindowStateTests extends WindowTestsBase { } @Test - public void testCantReceiveTouchWhenShouldIgnoreInput() { + public void testCantReceiveTouchWhenNotFocusable() { final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0"); - win0.mActivityRecord.getStack().setAdjustedForMinimizedDock(1 /* Any non 0 value works */); + win0.mActivityRecord.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + win0.mActivityRecord.getStack().setFocusable(false); assertTrue(win0.cantReceiveTouchInput()); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java index 9cda08458640..e5497a2313d1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationAnimationUtilsTest.java @@ -50,7 +50,7 @@ public class RotationAnimationUtilsTest { public void blackLuma() { Bitmap swBitmap = createBitmap(0); GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap); - float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace); + float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace); assertEquals(0, borderLuma, 0); } @@ -58,7 +58,15 @@ public class RotationAnimationUtilsTest { public void whiteLuma() { Bitmap swBitmap = createBitmap(1); GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap); - float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace); + float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace); + assertEquals(1, borderLuma, 0); + } + + @Test + public void unevenBitmapDimens() { + Bitmap swBitmap = createBitmap(1, BITMAP_WIDTH + 1, BITMAP_HEIGHT + 1); + GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap); + float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace); assertEquals(1, borderLuma, 0); } @@ -67,7 +75,7 @@ public class RotationAnimationUtilsTest { Bitmap swBitmap = createBitmap(1); setBorderLuma(swBitmap, 0); GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap); - float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace); + float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace); assertEquals(0, borderLuma, 0); } @@ -76,7 +84,7 @@ public class RotationAnimationUtilsTest { Bitmap swBitmap = createBitmap(0); setBorderLuma(swBitmap, 1); GraphicBuffer gb = swBitmapToGraphicsBuffer(swBitmap); - float borderLuma = RotationAnimationUtils.getAvgBorderLuma(gb, mColorSpace); + float borderLuma = RotationAnimationUtils.getMedianBorderLuma(gb, mColorSpace); assertEquals(1, borderLuma, 0); } @@ -123,9 +131,13 @@ public class RotationAnimationUtilsTest { } private Bitmap createBitmap(float luma) { - Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, ARGB_8888); - for (int i = 0; i < BITMAP_WIDTH; i++) { - for (int j = 0; j < BITMAP_HEIGHT; j++) { + return createBitmap(luma, BITMAP_WIDTH, BITMAP_HEIGHT); + } + + private Bitmap createBitmap(float luma, int width, int height) { + Bitmap bitmap = Bitmap.createBitmap(width, height, ARGB_8888); + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { bitmap.setPixel(i, j, Color.argb(1, luma, luma, luma)); } } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 07cc2d49d9e5..8e85bb23b5c7 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -1917,7 +1917,19 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser return; } try { - // Adbd will be started by AdbService once Global.ADB_ENABLED is set. + if ((config & UsbManager.FUNCTION_ADB) != 0) { + /** + * Start adbd if ADB function is included in the configuration. + */ + LocalServices.getService(AdbManagerInternal.class) + .startAdbdForTransport(AdbTransportType.USB); + } else { + /** + * Stop adbd otherwise + */ + LocalServices.getService(AdbManagerInternal.class) + .stopAdbdForTransport(AdbTransportType.USB); + } UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest, config, chargingFunctions); mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback, diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 3c0e0af67969..0b24dd2fe15a 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -60,7 +60,6 @@ import android.os.Trace; import android.os.UserHandle; import android.os.UserManagerInternal; import android.provider.Settings; -import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; import android.service.voice.VoiceInteractionManagerInternal; import android.service.voice.VoiceInteractionService; @@ -684,9 +683,9 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public void showSession(IVoiceInteractionService service, Bundle args, int flags) { + public void showSession(Bundle args, int flags) { synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); final long caller = Binder.clearCallingIdentity(); try { @@ -928,12 +927,10 @@ public class VoiceInteractionManagerService extends SystemService { } //----------------- Model management APIs --------------------------------// - // TODO: add check to only allow active voice interaction service or keyphrase enrollment - // application to manage voice models @Override public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { - enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); + enforceCallerAllowedToEnrollVoiceModel(); if (bcp47Locale == null) { throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); @@ -950,7 +947,7 @@ public class VoiceInteractionManagerService extends SystemService { @Override public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { - enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); + enforceCallerAllowedToEnrollVoiceModel(); if (model == null) { throw new IllegalArgumentException("Model must not be null"); } @@ -975,7 +972,7 @@ public class VoiceInteractionManagerService extends SystemService { @Override public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { - enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); + enforceCallerAllowedToEnrollVoiceModel(); if (bcp47Locale == null) { throw new IllegalArgumentException( @@ -1008,10 +1005,9 @@ public class VoiceInteractionManagerService extends SystemService { //----------------- SoundTrigger APIs --------------------------------// @Override - public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, - String bcp47Locale) { + public boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale) { synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); } if (bcp47Locale == null) { @@ -1030,10 +1026,10 @@ public class VoiceInteractionManagerService extends SystemService { } @Nullable - public KeyphraseMetadata getEnrolledKeyphraseMetadata(IVoiceInteractionService service, - String keyphrase, String bcp47Locale) { + public KeyphraseMetadata getEnrolledKeyphraseMetadata(String keyphrase, + String bcp47Locale) { synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); } if (bcp47Locale == null) { @@ -1065,10 +1061,10 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { + public ModuleProperties getDspModuleProperties() { // Allow the call if this is the current voice interaction service. synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); final long caller = Binder.clearCallingIdentity(); try { @@ -1080,12 +1076,11 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public int startRecognition(IVoiceInteractionService service, int keyphraseId, - String bcp47Locale, IRecognitionStatusCallback callback, - RecognitionConfig recognitionConfig) { + public int startRecognition(int keyphraseId, String bcp47Locale, + IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) { // Allow the call if this is the current voice interaction service. synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); if (callback == null || recognitionConfig == null || bcp47Locale == null) { throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); @@ -1117,11 +1112,10 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public int stopRecognition(IVoiceInteractionService service, int keyphraseId, - IRecognitionStatusCallback callback) { + public int stopRecognition(int keyphraseId, IRecognitionStatusCallback callback) { // Allow the call if this is the current voice interaction service. synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); } final long caller = Binder.clearCallingIdentity(); @@ -1133,11 +1127,10 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public int setParameter(IVoiceInteractionService service, int keyphraseId, - @ModelParams int modelParam, int value) { + public int setParameter(int keyphraseId, @ModelParams int modelParam, int value) { // Allow the call if this is the current voice interaction service. synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); } final long caller = Binder.clearCallingIdentity(); @@ -1149,11 +1142,10 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public int getParameter(IVoiceInteractionService service, int keyphraseId, - @ModelParams int modelParam) { + public int getParameter(int keyphraseId, @ModelParams int modelParam) { // Allow the call if this is the current voice interaction service. synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); } final long caller = Binder.clearCallingIdentity(); @@ -1166,11 +1158,10 @@ public class VoiceInteractionManagerService extends SystemService { @Override @Nullable - public ModelParamRange queryParameter(IVoiceInteractionService service, - int keyphraseId, @ModelParams int modelParam) { + public ModelParamRange queryParameter(int keyphraseId, @ModelParams int modelParam) { // Allow the call if this is the current voice interaction service. synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); } final long caller = Binder.clearCallingIdentity(); @@ -1400,9 +1391,9 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public void setUiHints(IVoiceInteractionService service, Bundle hints) { + public void setUiHints(Bundle hints) { synchronized (this) { - enforceIsCurrentVoiceInteractionService(service); + enforceIsCurrentVoiceInteractionService(); final int size = mVoiceInteractionSessionListeners.beginBroadcast(); for (int i = 0; i < size; ++i) { @@ -1425,14 +1416,32 @@ public class VoiceInteractionManagerService extends SystemService { } } - private void enforceIsCurrentVoiceInteractionService(IVoiceInteractionService service) { - if (mImpl == null || mImpl.mService == null - || service.asBinder() != mImpl.mService.asBinder()) { + private void enforceIsCurrentVoiceInteractionService() { + if (!isCallerCurrentVoiceInteractionService()) { throw new SecurityException("Caller is not the current voice interaction service"); } } + private void enforceCallerAllowedToEnrollVoiceModel() { + enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); + if (!isCallerCurrentVoiceInteractionService() + && !isCallerTrustedEnrollmentApplication()) { + throw new SecurityException("Caller is required to be the current voice interaction" + + " service or a system enrollment application to enroll voice models"); + } + } + + private boolean isCallerCurrentVoiceInteractionService() { + return mImpl != null + && mImpl.mInfo.getServiceInfo().applicationInfo.uid == Binder.getCallingUid(); + } + + private boolean isCallerTrustedEnrollmentApplication() { + return mImpl.mEnrollmentApplicationInfo.isUidSupportedEnrollmentApplication( + Binder.getCallingUid()); + } + private void setImplLocked(VoiceInteractionManagerServiceImpl impl) { mImpl = impl; mAtmInternal.notifyActiveVoiceInteractionServiceChanged( diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index a62b03ca82e4..b813f87f335f 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -36,6 +36,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; +import android.hardware.soundtrigger.KeyphraseEnrollmentInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -78,6 +79,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne final IActivityManager mAm; final IActivityTaskManager mAtm; final VoiceInteractionServiceInfo mInfo; + final KeyphraseEnrollmentInfo mEnrollmentApplicationInfo; final ComponentName mSessionComponentName; final IWindowManager mIWindowManager; boolean mBound = false; @@ -133,6 +135,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mComponent = service; mAm = ActivityManager.getService(); mAtm = ActivityTaskManager.getService(); + mEnrollmentApplicationInfo = new KeyphraseEnrollmentInfo(context.getPackageManager()); VoiceInteractionServiceInfo info; try { info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser); @@ -403,6 +406,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne pw.println(" Active session:"); mActiveSession.dump(" ", pw); } + pw.println(" " + mEnrollmentApplicationInfo.toString()); } void startLocked() { diff --git a/startop/iorap/functional_tests/AndroidTest.xml b/startop/iorap/functional_tests/AndroidTest.xml index ef56fc827420..3d5a2294f8d5 100644 --- a/startop/iorap/functional_tests/AndroidTest.xml +++ b/startop/iorap/functional_tests/AndroidTest.xml @@ -48,6 +48,8 @@ <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.google.android.startop.iorap.tests" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <!-- test-timeout unit is ms, value = 30 min --> + <option name="test-timeout" value="1800000" /> </test> </configuration> diff --git a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java b/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java index 40023878af19..9abbcd71cfd2 100644 --- a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java +++ b/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java @@ -70,7 +70,7 @@ public class IorapWorkFlowTest { private static final Duration TIMEOUT = Duration.ofSeconds(300L); private static final String READAHEAD_INDICATOR = - "Description = /data/misc/iorapd/com.android.settings/none/com.android.settings.Settings/compiled_traces/compiled_trace.pb"; + "Description = /data/misc/iorapd/com.android.settings/-?\\d+/com.android.settings.Settings/compiled_traces/compiled_trace.pb"; private UiDevice mDevice; @@ -326,14 +326,14 @@ public class IorapWorkFlowTest { return false; } - String log = executeShellCommand("logcat -s iorapd -d"); + String log = executeShellCommand("logcat -d"); Pattern p = Pattern.compile( - ".*" + READAHEAD_INDICATOR - + ".*Total File Paths=(\\d+) \\(good: (\\d+)%\\)\n" - + ".*Total Entries=(\\d+) \\(good: (\\d+)%\\)\n" - + ".*Total Bytes=(\\d+) \\(good: (\\d+)%\\).*", - Pattern.DOTALL); + ".*" + READAHEAD_INDICATOR + + ".*Total File Paths=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n" + + ".*Total Entries=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n" + + ".*Total Bytes=(\\d+) \\(good: (\\d+[.]?\\d*)%\\).*", + Pattern.DOTALL); Matcher m = p.matcher(log); if (!m.matches()) { diff --git a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java b/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java index 9b3bfcb0fa4a..2055b206dd7a 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java +++ b/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java @@ -40,7 +40,7 @@ public class JobScheduledEvent implements Parcelable { public static final int TYPE_START_JOB = 0; /** JobService#onJobStopped */ public static final int TYPE_STOP_JOB = 1; - private static final int TYPE_MAX = 0; + private static final int TYPE_MAX = 1; /** @hide */ @IntDef(flag = true, prefix = { "TYPE_" }, value = { diff --git a/startop/scripts/app_startup/parse_metrics b/startop/scripts/app_startup/parse_metrics index 036609ff02be..3fa1462bc56e 100755 --- a/startop/scripts/app_startup/parse_metrics +++ b/startop/scripts/app_startup/parse_metrics @@ -42,12 +42,14 @@ Usage: launch_application package activity | parse_metrics --package <name> --ti -h, --help usage information (this) -v, --verbose enable extra verbose printing -t, --timeout <sec> how many seconds to timeout when trying to wait for logcat to change + -rfd, --reportfullydrawn wait for report fully drawn (default: off) EOF } DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source "$DIR/lib/common" +report_fully_drawn="n" package="" activity="" timeout=5 @@ -81,6 +83,11 @@ parse_arguments() { -s|--simulate) simulate="y" ;; + -rfd|--reportfullydrawn) + report_fully_drawn="y" + ;; + + *) echo "Invalid argument: $1" >&2 exit 1 @@ -190,12 +197,15 @@ re_pattern='.*Displayed[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\ parse_metric_from_logcat "Displayed_ms" "$pattern" "$re_pattern" -# 01-16 17:31:44.550 11172 11204 I ActivityTaskManager: Fully drawn com.google.android.GoogleCamera/com.android.camera.CameraLauncher: +10s897ms -pattern="ActivityTaskManager: Fully drawn ${package}" -#re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+\).*' -re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*' +# Only track ReportFullyDrawn with --reportfullydrawn/-rfd flags +if [[ $report_fully_drawn == y ]]; then + # 01-16 17:31:44.550 11172 11204 I ActivityTaskManager: Fully drawn com.google.android.GoogleCamera/com.android.camera.CameraLauncher: +10s897ms + pattern="ActivityTaskManager: Fully drawn ${package}" + #re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+\).*' + re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*' -parse_metric_from_logcat "Fully_drawn_ms" "$pattern" "$re_pattern" + parse_metric_from_logcat "Fully_drawn_ms" "$pattern" "$re_pattern" +fi # also call into package-specific scripts if there are additional metrics if [[ -x "$DIR/metrics/$package" ]]; then diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch index 92a31c30a12d..31f625334b1e 100755 --- a/startop/scripts/app_startup/run_app_with_prefetch +++ b/startop/scripts/app_startup/run_app_with_prefetch @@ -35,6 +35,7 @@ EOF DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source "$DIR/../iorap/common" +report_fully_drawn="n" needs_trace_file="n" input_file="" package="" @@ -70,6 +71,10 @@ parse_arguments() { mode="$2" shift ;; + -rfd|--reportfullydrawn) + report_fully_drawn="y" + shift + ;; -c|--count) count="$2" ((count+=1)) @@ -403,7 +408,11 @@ parse_metrics_header() { join_by ',' "${all_metrics[@]}" } -metrics_header="$("$DIR/parse_metrics" --package "$package" --activity "$activity" --simulate | parse_metrics_header)" +if [[ $report_fully_drawn == y ]]; then + metrics_header="$("$DIR/parse_metrics" --package "$package" --activity "$activity" --simulate --reportfullydrawn | parse_metrics_header)" +else + metrics_header="$("$DIR/parse_metrics" --package "$package" --activity "$activity" --simulate | parse_metrics_header)" +fi # TODO: This loop logic could probably be moved into app_startup_runner.py for ((i=0;i<count;++i)) do @@ -411,6 +420,9 @@ for ((i=0;i<count;++i)) do verbose_print "==== ITERATION $i ====" verbose_print "==========================================" if [[ $mode != "warm" ]]; then + # The package must be killed **before** we drop caches, otherwise pages will stay resident. + verbose_print "Kill package for non-warm start." + remote_pkill "$package" verbose_print "Drop caches for non-warm start." # Drop all caches to get cold starts. adb shell "echo 3 > /proc/sys/vm/drop_caches" @@ -423,7 +435,12 @@ for ((i=0;i<count;++i)) do pre_launch_timestamp="$(logcat_save_timestamp)" # TODO: multiple metrics output. + +if [[ $report_fully_drawn == y ]]; then + total_time="$(timeout $timeout "$DIR/launch_application" "$package" "$activity" | "$DIR/parse_metrics" --package "$package" --activity "$activity" --timestamp "$pre_launch_timestamp" --reportfullydrawn | parse_metrics_output)" +else total_time="$(timeout $timeout "$DIR/launch_application" "$package" "$activity" | "$DIR/parse_metrics" --package "$package" --activity "$activity" --timestamp "$pre_launch_timestamp" | parse_metrics_output)" +fi if [[ $? -ne 0 ]]; then echo "WARNING: Skip bad result, try iteration again." >&2 diff --git a/startop/scripts/app_startup/run_app_with_prefetch.py b/startop/scripts/app_startup/run_app_with_prefetch.py index 2f1eff2c41f6..2f1eff2c41f6 100644..100755 --- a/startop/scripts/app_startup/run_app_with_prefetch.py +++ b/startop/scripts/app_startup/run_app_with_prefetch.py diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 9d7762359f6b..6a40487f44eb 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4096,7 +4096,8 @@ public class CarrierConfigManager { /** Prefix of all Wifi.KEY_* constants. */ public static final String KEY_PREFIX = "wifi."; /** - * It contains the maximum client count definition that the carrier owns. + * It contains the maximum client count definition that the carrier sets. + * The default is 0, which means that the carrier hasn't set a requirement. */ public static final String KEY_HOTSPOT_MAX_CLIENT_COUNT = KEY_PREFIX + "hotspot_maximum_client_count"; diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java index bc8473865466..90ddf2cd4730 100644 --- a/telephony/java/android/telephony/RadioAccessFamily.java +++ b/telephony/java/android/telephony/RadioAccessFamily.java @@ -260,24 +260,6 @@ public class RadioAccessFamily implements Parcelable { return raf; } - /** - * Returns the highest capability of the RadioAccessFamily (4G > 3G > 2G). - * @param raf The RadioAccessFamily that we wish to filter - * @return The highest radio capability - */ - public static int getHighestRafCapability(int raf) { - if ((LTE & raf) > 0) { - return TelephonyManager.NETWORK_CLASS_4_G; - } - if ((EVDO|HS|WCDMA & raf) > 0) { - return TelephonyManager.NETWORK_CLASS_3_G; - } - if((GSM|CDMA & raf) > 0) { - return TelephonyManager.NETWORK_CLASS_2_G; - } - return TelephonyManager.NETWORK_CLASS_UNKNOWN; - } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) @PrefNetworkMode public static int getNetworkTypeFromRaf(int raf) { @@ -395,4 +377,34 @@ public class RadioAccessFamily implements Parcelable { } return result; } + + /** + * Compare two sets of network types to see which is more capable. + * + * This algorithm first tries to see see if a set has a strict superset of RAT support for + * each generation, from newest to oldest; if that results in a tie, then it returns the set + * that supports the most RAT types. + */ + public static int compare(long networkTypeBitmaskL, long networkTypeBitmaskR) { + final long[] prioritizedNetworkClassBitmasks = new long[] { + TelephonyManager.NETWORK_CLASS_BITMASK_5G, + TelephonyManager.NETWORK_CLASS_BITMASK_4G, + TelephonyManager.NETWORK_CLASS_BITMASK_3G, + TelephonyManager.NETWORK_CLASS_BITMASK_2G, + }; + + long lhsUnique = networkTypeBitmaskL & ~networkTypeBitmaskR; + long rhsUnique = networkTypeBitmaskR & ~networkTypeBitmaskL; + + // See if one has a strict super-set of capabilities, generation by generation. + for (long classBitmask : prioritizedNetworkClassBitmasks) { + int result = 0; + if ((lhsUnique & classBitmask) != 0) ++result; + if ((rhsUnique & classBitmask) != 0) --result; + if (result != 0) return result; + } + + // Without a clear winner, return the one that supports the most types. + return Long.bitCount(networkTypeBitmaskL) - Long.bitCount(networkTypeBitmaskR); + } } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index a5a1ebc10139..e957f3e3d70f 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -1992,7 +1992,6 @@ public class ServiceState implements Parcelable { * @return the copied ServiceState with location info sanitized. * @hide */ - @SystemApi @NonNull public ServiceState createLocationInfoSanitizedCopy(boolean removeCoarseLocation) { ServiceState state = new ServiceState(this); diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 336aa0e6bda6..0ec3d55efe3b 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -826,7 +826,7 @@ public class SubscriptionInfo implements Parcelable { + " hplmns=" + Arrays.toString(mHplmns) + " subscriptionType=" + mSubscriptionType + " mGroupOwner=" + mGroupOwner - + " carrierConfigAccessRules=" + mCarrierConfigAccessRules + + " carrierConfigAccessRules=" + Arrays.toString(mCarrierConfigAccessRules) + " mAreUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled + "}"; } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index b32e9d73a141..8ac9023b33dc 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2575,8 +2575,8 @@ public class SubscriptionManager { * @hide */ @SystemApi - public boolean canManageSubscription(@Nullable SubscriptionInfo info, - @Nullable String packageName) { + public boolean canManageSubscription(@NonNull SubscriptionInfo info, + @NonNull String packageName) { if (info == null || info.getAllAccessRules() == null || packageName == null) { return false; } @@ -3081,13 +3081,13 @@ public class SubscriptionManager { * * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required * - * @param enabled whether uicc applications are enabled or disabled. * @param subscriptionId which subscription to operate on. + * @param enabled whether uicc applications are enabled or disabled. * @hide */ @SystemApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) - public void setUiccApplicationsEnabled(boolean enabled, int subscriptionId) { + public void setUiccApplicationsEnabled(int subscriptionId, boolean enabled) { if (VDBG) { logd("setUiccApplicationsEnabled subId= " + subscriptionId + " enable " + enabled); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0660776c3868..51e777e4db4e 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2788,39 +2788,22 @@ public class TelephonyManager { /** * Returns the ISO-3166 country code equivalent of the MCC (Mobile Country Code) of the current * registered operator or the cell nearby, if available. - * <p> - * The ISO-3166 country code is provided in lowercase 2 character format. - * <p> - * Note: In multi-sim, this returns a shared emergency network country iso from other - * subscription if the subscription used to create the TelephonyManager doesn't camp on - * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding - * slot. + * * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine * if on a CDMA network). * <p> * @return the lowercase 2 character ISO-3166 country code, or empty string if not available. */ public String getNetworkCountryIso() { - try { - ITelephony telephony = getITelephony(); - if (telephony == null) return ""; - return telephony.getNetworkCountryIsoForPhone(getPhoneId(), - null /* no permission check */, null); - } catch (RemoteException ex) { - return ""; - } + return getNetworkCountryIso(getSlotIndex()); } /** * Returns the ISO-3166 country code equivalent of the MCC (Mobile Country Code) of the current - * registered operator or the cell nearby, if available. - * <p> - * The ISO-3166 country code is provided in lowercase 2 character format. - * <p> - * Note: In multi-sim, this returns a shared emergency network country iso from other - * subscription if the subscription used to create the TelephonyManager doesn't camp on - * a network due to some reason (e.g. pin/puk locked), or sim is absent in the corresponding - * slot. + * registered operator or the cell nearby, if available. This is same as + * {@link #getNetworkCountryIso()} but allowing specifying the SIM slot index. This is used for + * accessing network country info from the SIM slot that does not have SIM inserted. + * * Note: Result may be unreliable on CDMA networks (use {@link #getPhoneType()} to determine * if on a CDMA network). * <p> @@ -2831,22 +2814,18 @@ public class TelephonyManager { * * @throws IllegalArgumentException when the slotIndex is invalid. * - * {@hide} */ - @SystemApi - @TestApi @NonNull - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getNetworkCountryIso(int slotIndex) { try { - if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { + if (slotIndex != SubscriptionManager.DEFAULT_SIM_SLOT_INDEX + && !SubscriptionManager.isValidSlotIndex(slotIndex)) { throw new IllegalArgumentException("invalid slot index " + slotIndex); } ITelephony telephony = getITelephony(); if (telephony == null) return ""; - return telephony.getNetworkCountryIsoForPhone(slotIndex, getOpPackageName(), - getFeatureId()); + return telephony.getNetworkCountryIsoForPhone(slotIndex); } catch (RemoteException ex) { return ""; } @@ -3096,64 +3075,6 @@ public class TelephonyManager { } /** - * Network Class Definitions. - * Do not change this order, it is used for sorting during emergency calling in - * {@link TelephonyConnectionService#getFirstPhoneForEmergencyCall()}. Any newer technologies - * should be added after the current definitions. - */ - /** Unknown network class. {@hide} */ - public static final int NETWORK_CLASS_UNKNOWN = 0; - /** Class of broadly defined "2G" networks. {@hide} */ - @UnsupportedAppUsage - public static final int NETWORK_CLASS_2_G = 1; - /** Class of broadly defined "3G" networks. {@hide} */ - @UnsupportedAppUsage - public static final int NETWORK_CLASS_3_G = 2; - /** Class of broadly defined "4G" networks. {@hide} */ - @UnsupportedAppUsage - public static final int NETWORK_CLASS_4_G = 3; - /** Class of broadly defined "5G" networks. {@hide} */ - public static final int NETWORK_CLASS_5_G = 4; - - /** - * Return general class of network type, such as "3G" or "4G". In cases - * where classification is contentious, this method is conservative. - * - * @hide - */ - @UnsupportedAppUsage - public static int getNetworkClass(int networkType) { - switch (networkType) { - case NETWORK_TYPE_GPRS: - case NETWORK_TYPE_GSM: - case NETWORK_TYPE_EDGE: - case NETWORK_TYPE_CDMA: - case NETWORK_TYPE_1xRTT: - case NETWORK_TYPE_IDEN: - return NETWORK_CLASS_2_G; - case NETWORK_TYPE_UMTS: - case NETWORK_TYPE_EVDO_0: - case NETWORK_TYPE_EVDO_A: - case NETWORK_TYPE_HSDPA: - case NETWORK_TYPE_HSUPA: - case NETWORK_TYPE_HSPA: - case NETWORK_TYPE_EVDO_B: - case NETWORK_TYPE_EHRPD: - case NETWORK_TYPE_HSPAP: - case NETWORK_TYPE_TD_SCDMA: - return NETWORK_CLASS_3_G; - case NETWORK_TYPE_LTE: - case NETWORK_TYPE_IWLAN: - case NETWORK_TYPE_LTE_CA: - return NETWORK_CLASS_4_G; - case NETWORK_TYPE_NR: - return NETWORK_CLASS_5_G; - default: - return NETWORK_CLASS_UNKNOWN; - } - } - - /** * Returns a string representation of the radio technology (network type) * currently in use on the device. * @return the name of the radio technology @@ -8028,21 +7949,19 @@ public class TelephonyManager { * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @param operatorNumeric the PLMN ID of the network to select. + * @param persistSelection whether the selection will persist until reboot. + * If true, only allows attaching to the selected PLMN until reboot; otherwise, + * attach to the chosen PLMN and resume normal network selection next time. * @param ran the initial suggested radio access network type. * If registration fails, the RAN is not available after, the RAN is not within the - * network types specified by {@link #setPreferredNetworkTypeBitmask}, or the value is + * network types specified by the preferred network types, or the value is * {@link AccessNetworkConstants.AccessNetworkType#UNKNOWN}, modem will select * the next best RAN for network registration. - * @param persistSelection whether the selection will persist until reboot. - * If true, only allows attaching to the selected PLMN until reboot; otherwise, - * attach to the chosen PLMN and resume normal network selection next time. * @return {@code true} on success; {@code false} on any failure. - * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - @SystemApi public boolean setNetworkSelectionModeManual(@NonNull String operatorNumeric, - @AccessNetworkConstants.RadioAccessNetworkType int ran, boolean persistSelection) { + boolean persistSelection, @AccessNetworkConstants.RadioAccessNetworkType int ran) { return setNetworkSelectionModeManual(new OperatorInfo("" /* operatorAlphaLong */, "" /* operatorAlphaShort */, operatorNumeric, ran), persistSelection); } @@ -11092,7 +11011,6 @@ public class TelephonyManager { * @param enabled True if enabling the data, otherwise disabling. * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setPolicyDataEnabled(boolean enabled) { try { @@ -11195,7 +11113,6 @@ public class TelephonyManager { * @param isEnabled {@code true} for enabling; {@code false} for disabling. * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAlwaysReportSignalStrength(boolean isEnabled) { try { @@ -11623,6 +11540,55 @@ public class TelephonyManager { @SystemApi public static final long NETWORK_TYPE_BITMASK_IWLAN = (1 << (NETWORK_TYPE_IWLAN -1)); + /** @hide */ + public static final long NETWORK_CLASS_BITMASK_2G = NETWORK_TYPE_BITMASK_GSM + | NETWORK_TYPE_BITMASK_GPRS + | NETWORK_TYPE_BITMASK_EDGE + | NETWORK_TYPE_BITMASK_CDMA + | NETWORK_TYPE_BITMASK_1xRTT; + + /** @hide */ + public static final long NETWORK_CLASS_BITMASK_3G = NETWORK_TYPE_BITMASK_EVDO_0 + | NETWORK_TYPE_BITMASK_EVDO_A + | NETWORK_TYPE_BITMASK_EVDO_B + | NETWORK_TYPE_BITMASK_EHRPD + | NETWORK_TYPE_BITMASK_HSUPA + | NETWORK_TYPE_BITMASK_HSDPA + | NETWORK_TYPE_BITMASK_HSPA + | NETWORK_TYPE_BITMASK_HSPAP + | NETWORK_TYPE_BITMASK_UMTS + | NETWORK_TYPE_BITMASK_TD_SCDMA; + + /** @hide */ + public static final long NETWORK_CLASS_BITMASK_4G = NETWORK_TYPE_BITMASK_LTE + | NETWORK_TYPE_BITMASK_LTE_CA + | NETWORK_TYPE_BITMASK_IWLAN; + + /** @hide */ + public static final long NETWORK_CLASS_BITMASK_5G = NETWORK_TYPE_BITMASK_NR; + + /** @hide */ + public static final long NETWORK_STANDARDS_FAMILY_BITMASK_3GPP = NETWORK_TYPE_BITMASK_GSM + | NETWORK_TYPE_BITMASK_GPRS + | NETWORK_TYPE_BITMASK_EDGE + | NETWORK_TYPE_BITMASK_HSUPA + | NETWORK_TYPE_BITMASK_HSDPA + | NETWORK_TYPE_BITMASK_HSPA + | NETWORK_TYPE_BITMASK_HSPAP + | NETWORK_TYPE_BITMASK_UMTS + | NETWORK_TYPE_BITMASK_TD_SCDMA + | NETWORK_TYPE_BITMASK_LTE + | NETWORK_TYPE_BITMASK_LTE_CA + | NETWORK_TYPE_BITMASK_NR; + + /** @hide */ + public static final long NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2 = NETWORK_TYPE_BITMASK_CDMA + | NETWORK_TYPE_BITMASK_1xRTT + | NETWORK_TYPE_BITMASK_EVDO_0 + | NETWORK_TYPE_BITMASK_EVDO_A + | NETWORK_TYPE_BITMASK_EVDO_B + | NETWORK_TYPE_BITMASK_EHRPD; + /** * @return Modem supported radio access family bitmask * diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 861925fd66e5..af5089f8e0d9 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -281,7 +281,7 @@ interface ITelephony { * operator's MCC (Mobile Country Code). * @see android.telephony.TelephonyManager#getNetworkCountryIso */ - String getNetworkCountryIsoForPhone(int phoneId, String callingPkg, String callingFeatureId); + String getNetworkCountryIsoForPhone(int phoneId); /** * Returns the neighboring cell information of the device. diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java index 2c6604759813..784ee85fea34 100644 --- a/test-mock/src/android/test/mock/MockContext.java +++ b/test-mock/src/android/test/mock/MockContext.java @@ -17,7 +17,6 @@ package android.test.mock; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.IApplicationThread; import android.app.IServiceConnection; @@ -480,10 +479,11 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ @Override - public void sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, - Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, - String initialData, Bundle initialExtras) { + public void sendOrderedBroadcast(Intent intent, int initialCode, String receiverPermission, + String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, + String initialData, Bundle initialExtras, Bundle options) { throw new UnsupportedOperationException(); } diff --git a/tests/BootImageProfileTest/DISABLED_TEST_MAPPING b/tests/BootImageProfileTest/TEST_MAPPING index 1b569f9455bf..1b569f9455bf 100644 --- a/tests/BootImageProfileTest/DISABLED_TEST_MAPPING +++ b/tests/BootImageProfileTest/TEST_MAPPING diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java index 1c8b6be49547..61f3dbaff1a3 100644 --- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java +++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java @@ -30,6 +30,7 @@ public class BootImageProfileTest implements IDeviceTest { private ITestDevice mTestDevice; private static final String SYSTEM_SERVER_PROFILE = "/data/misc/profiles/cur/0/android/primary.prof"; + private static final boolean USE_PHENOTYPE = false; @Override public void setDevice(ITestDevice testDevice) { @@ -41,16 +42,33 @@ public class BootImageProfileTest implements IDeviceTest { return mTestDevice; } + private String getProperty(String property) throws Exception { + if (USE_PHENOTYPE) { + return mTestDevice.getProperty("persist.device_config.runtime_native_boot." + + property); + } else { + return mTestDevice.executeShellCommand("getprop dalvik.vm." + property).trim(); + } + } + + private String setProperty(String property, String value) throws Exception { + if (USE_PHENOTYPE) { + return mTestDevice.executeShellCommand( + "device_config put runtime_native_boot " + property + " " + value); + } else { + return mTestDevice.executeShellCommand( + "setprop dalvik.vm." + property + " " + value); + } + } + /** * Validate that the boot image profile properties are set. */ public void validateProperties() throws Exception { - String res = mTestDevice.getProperty( - "persist.device_config.runtime_native_boot.profilebootclasspath"); - assertTrue("profile boot class path not enabled", res != null && res.equals("true")); - res = mTestDevice.getProperty( - "persist.device_config.runtime_native_boot.profilesystemserver"); - assertTrue("profile system server not enabled", res != null && res.equals("true")); + String res = getProperty("profilebootclasspath"); + assertTrue("profile boot class path not enabled: " + res, "true".equals(res)); + res = getProperty("profilesystemserver"); + assertTrue("profile system server not enabled: " + res, "true".equals(res)); } private boolean forceSaveProfile(String pkg) throws Exception { @@ -67,33 +85,48 @@ public class BootImageProfileTest implements IDeviceTest { @Test public void testSystemServerProfile() throws Exception { final int numIterations = 20; + String res; + // Set properties and wait for them to be readable. for (int i = 1; i <= numIterations; ++i) { - String res; - res = mTestDevice.getProperty( - "persist.device_config.runtime_native_boot.profilebootclasspath"); - boolean profileBootClassPath = res != null && res.equals("true"); - res = mTestDevice.getProperty( - "persist.device_config.runtime_native_boot.profilesystemserver"); - boolean profileSystemServer = res != null && res.equals("true"); + String pbcp = getProperty("profilebootclasspath"); + boolean profileBootClassPath = "true".equals(pbcp); + String pss = getProperty("profilesystemserver"); + boolean profileSystemServer = "true".equals(pss); if (profileBootClassPath && profileSystemServer) { break; } if (i == numIterations) { - assertTrue("profile system server not enabled", profileSystemServer); - assertTrue("profile boot class path not enabled", profileSystemServer); + assertTrue("profile system server not enabled: " + pss, profileSystemServer); + assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath); } - res = mTestDevice.executeShellCommand( - "device_config put runtime_native_boot profilebootclasspath true"); - res = mTestDevice.executeShellCommand( - "device_config put runtime_native_boot profilesystemserver true"); - res = mTestDevice.executeShellCommand("stop"); - res = mTestDevice.executeShellCommand("start"); - Thread.sleep(5000); + setProperty("profilebootclasspath", "true"); + setProperty("profilesystemserver", "true"); + Thread.sleep(1000); } + + // Restart shell and wait for system boot. + res = mTestDevice.executeShellCommand("stop"); + assertTrue("stop shell: " + res, res.length() == 0); + res = mTestDevice.executeShellCommand("start"); + assertTrue("start shell: " + res, res.length() == 0); + for (int i = 1; i <= numIterations; ++i) { + String pbcp = getProperty("profilebootclasspath"); + boolean profileBootClassPath = "true".equals(pbcp); + String pss = getProperty("profilesystemserver"); + boolean profileSystemServer = "true".equals(pss); + if (profileBootClassPath && profileSystemServer) { + break; + } + if (i == numIterations) { + assertTrue("profile system server not enabled: " + pss, profileSystemServer); + assertTrue("profile boot class path not enabled: " + pbcp, profileBootClassPath); + } + Thread.sleep(1000); + } + // Trunacte the profile before force it to be saved to prevent previous profiles // causing the test to pass. - String res; res = mTestDevice.executeShellCommand("truncate -s 0 " + SYSTEM_SERVER_PROFILE).trim(); assertTrue(res, res.length() == 0); // Wait up to 20 seconds for the profile to be saved. diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamIncompleteValueTest.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamIncompleteValueTest.java new file mode 100644 index 000000000000..167d5a438302 --- /dev/null +++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoInputStreamIncompleteValueTest.java @@ -0,0 +1,180 @@ +/* + * 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.test.protoinputstream; + +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoParseException; +import android.util.proto.ProtoStream; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ProtoInputStreamIncompleteValueTest extends TestCase { + + /** + * Test that an incomplete varint at the end of a stream throws an exception + */ + public void testIncompleteVarint() throws IOException { + final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32; + + final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL); + + final byte[] protobuf = new byte[]{ + // 1 : varint -> invalid varint value + (byte) 0x08, + (byte) 0xff, + }; + + InputStream stream = new ByteArrayInputStream(protobuf); + final ProtoInputStream pi = new ProtoInputStream(stream); + + while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + try { + switch (pi.getFieldNumber()) { + case (int) fieldId1: + pi.readInt(fieldId1); + fail("Should have thrown a ProtoParseException"); + break; + default: + fail("Unexpected field id " + pi.getFieldNumber()); + } + } catch (ProtoParseException ppe) { + // good + stream.close(); + return; + } + } + stream.close(); + fail("Test should not have reached this point..."); + } + + /** + * Test that an incomplete fixed64 at the end of a stream throws an exception + */ + public void testIncompleteFixed64() throws IOException { + final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64; + + final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL); + + final byte[] protobuf = new byte[]{ + // 2 -> invalid fixed64 + (byte) 0x11, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, + }; + + InputStream stream = new ByteArrayInputStream(protobuf); + final ProtoInputStream pi = new ProtoInputStream(stream); + + while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + try { + switch (pi.getFieldNumber()) { + case (int) fieldId2: + pi.readLong(fieldId2); + fail("Should have thrown a ProtoParseException"); + break; + default: + fail("Unexpected field id " + pi.getFieldNumber()); + } + } catch (ProtoParseException ppe) { + // good + stream.close(); + return; + } + } + stream.close(); + fail("Test should not have reached this point..."); + } + + /** + * Test that an incomplete length delimited value at the end of a stream throws an exception + */ + public void testIncompleteLengthDelimited() throws IOException { + final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES; + + final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL); + + final byte[] protobuf = new byte[]{ + // 5 -> invalid byte array (has size 5 but only 4 values) + (byte) 0x2a, + (byte) 0x05, + (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, + }; + + InputStream stream = new ByteArrayInputStream(protobuf); + final ProtoInputStream pi = new ProtoInputStream(stream); + + while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + try { + switch (pi.getFieldNumber()) { + case (int) fieldId5: + pi.readBytes(fieldId5); + fail("Should have thrown a ProtoParseException"); + break; + default: + fail("Unexpected field id " + pi.getFieldNumber()); + } + } catch (ProtoParseException ppe) { + // good + stream.close(); + return; + } + } + stream.close(); + fail("Test should not have reached this point..."); + } + + /** + * Test that an incomplete fixed32 at the end of a stream throws an exception + */ + public void testIncompleteFixed32() throws IOException { + final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32; + + final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL); + + final byte[] protobuf = new byte[]{ + // 2 -> invalid fixed32 + (byte) 0x15, + (byte) 0x01, (byte) 0x00, (byte) 0x00, + }; + + InputStream stream = new ByteArrayInputStream(protobuf); + final ProtoInputStream pi = new ProtoInputStream(stream); + + while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + try { + switch (pi.getFieldNumber()) { + case (int) fieldId2: + pi.readInt(fieldId2); + fail("Should have thrown a ProtoParseException"); + break; + default: + fail("Unexpected field id " + pi.getFieldNumber()); + } + } catch (ProtoParseException ppe) { + // good + stream.close(); + return; + } + } + stream.close(); + fail("Test should not have reached this point..."); + } +} diff --git a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoTests.java b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoTests.java index cdf6ae20f370..685110c08147 100644 --- a/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoTests.java +++ b/tests/ProtoInputStreamTests/src/com/android/test/protoinputstream/ProtoTests.java @@ -39,6 +39,7 @@ public class ProtoTests { suite.addTestSuite(ProtoInputStreamBytesTest.class); suite.addTestSuite(ProtoInputStreamEnumTest.class); suite.addTestSuite(ProtoInputStreamObjectTest.class); + suite.addTestSuite(ProtoInputStreamIncompleteValueTest.class); return suite; } diff --git a/tests/RollbackTest/NetworkStagedRollbackTest.xml b/tests/RollbackTest/NetworkStagedRollbackTest.xml index a465a4fe578b..2ab907a59298 100644 --- a/tests/RollbackTest/NetworkStagedRollbackTest.xml +++ b/tests/RollbackTest/NetworkStagedRollbackTest.xml @@ -19,6 +19,12 @@ <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="RollbackTest.apk" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package "com.google.android.gms.platformconfigurator" --es user '\\*' --esa flags "ModuleConfig__immediate_commit_packages" --esa types "bytes" --esa values "CgA=" com.google.android.gms" /> + <option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package "com.google.android.gms.platformconfigurator" --es user '\\*' --esa flags "ModuleConfig__versioned_immediate_commit_packages" --esa types "bytes" --esa values "Cm5vdGFwYWNrYWdlOgA=" com.google.android.gms" /> + <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package "com.google.android.gms.platformconfigurator" --es user '\*' --esa flag "ModuleConfig__immediate_commit_packages" com.google.android.gms" /> + <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package "com.google.android.gms.platformconfigurator" --es user '\*' --esa flag "ModuleConfig__versioned_immediate_commit_packages" com.google.android.gms" /> + </target_preparer> <test class="com.android.tradefed.testtype.HostTest" > <option name="class" value="com.android.tests.rollback.host.NetworkStagedRollbackTest" /> </test> diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 6f442300bce7..c1d05e47bc19 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -59,6 +59,7 @@ cc_defaults { "libprotobuf-cpp-full", "libz", "libbuildversion", + "libidmap2_policies", ], stl: "libc++_static", group_static_libs: true, diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index 137fbd671865..1eb7d95f381a 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -32,10 +32,16 @@ #include "text/Printer.h" #include "util/Util.h" +#include "idmap2/Policies.h" + using ::aapt::text::Printer; using ::android::StringPiece; using ::android::base::StringPrintf; +using android::idmap2::policy::kPolicyStringToFlag; + +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { namespace { @@ -246,32 +252,25 @@ class ValueBodyPrinter : public ConstValueVisitor { Printer* printer_; }; -std::string OverlayablePoliciesToString(OverlayableItem::PolicyFlags policies) { - static const std::map<OverlayableItem::PolicyFlags, std::string> kFlagToString = { - {OverlayableItem::kPublic, "public"}, - {OverlayableItem::kSystem, "system"}, - {OverlayableItem::kVendor, "vendor"}, - {OverlayableItem::kProduct, "product"}, - {OverlayableItem::kSignature, "signature"}, - {OverlayableItem::kOdm, "odm"}, - {OverlayableItem::kOem, "oem"}, - }; +std::string OverlayablePoliciesToString(PolicyFlags policies) { std::string str; - for (auto const& policy : kFlagToString) { - if ((policies & policy.first) != policy.first) { + + uint32_t remaining = policies; + for (auto const& policy : kPolicyStringToFlag) { + if ((policies & policy.second) != policy.second) { continue; } if (!str.empty()) { str.append("|"); } - str.append(policy.second); - policies &= ~policy.first; + str.append(policy.first.data()); + remaining &= ~policy.second; } - if (policies != 0) { + if (remaining != 0) { if (!str.empty()) { str.append("|"); } - str.append(StringPrintf("0x%08x", policies)); + str.append(StringPrintf("0x%08x", remaining)); } return !str.empty() ? str : "none"; } diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 74e2a0987c3f..234cbc4b37e0 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -32,11 +32,15 @@ #include "util/Util.h" #include "xml/XmlPullParser.h" +#include "idmap2/Policies.h" + using ::aapt::ResourceUtils::StringBuilder; using ::aapt::text::Utf8Iterator; using ::android::ConfigDescription; using ::android::StringPiece; +using android::idmap2::policy::kPolicyStringToFlag; + namespace aapt { constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2"; @@ -1063,7 +1067,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource bool error = false; std::string comment; - OverlayableItem::PolicyFlags current_policies = OverlayableItem::Policy::kNone; + PolicyFlags current_policies = PolicyFlags::NONE; const size_t start_depth = parser->depth(); while (xml::XmlPullParser::IsGoodEvent(parser->Next())) { xml::XmlPullParser::Event event = parser->event(); @@ -1073,7 +1077,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource } else if (event == xml::XmlPullParser::Event::kEndElement && parser->depth() == start_depth + 1) { // Clear the current policies when exiting the <policy> tags - current_policies = OverlayableItem::Policy::kNone; + current_policies = PolicyFlags::NONE; continue; } else if (event == xml::XmlPullParser::Event::kComment) { // Retrieve the comment of individual <item> tags @@ -1088,7 +1092,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource const std::string& element_name = parser->element_name(); const std::string& element_namespace = parser->element_namespace(); if (element_namespace.empty() && element_name == "item") { - if (current_policies == OverlayableItem::Policy::kNone) { + if (current_policies == PolicyFlags::NONE) { diag_->Error(DiagMessage(element_source) << "<item> within an <overlayable> must be inside a <policy> block"); error = true; @@ -1133,7 +1137,7 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource out_resource->child_resources.push_back(std::move(child_resource)); } else if (element_namespace.empty() && element_name == "policy") { - if (current_policies != OverlayableItem::Policy::kNone) { + if (current_policies != PolicyFlags::NONE) { // If the policy list is not empty, then we are currently inside a policy element diag_->Error(DiagMessage(element_source) << "<policy> blocks cannot be recursively nested"); error = true; @@ -1141,21 +1145,14 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) { // Parse the polices separated by vertical bar characters to allow for specifying multiple // policies. Items within the policy tag will have the specified policy. - static const auto kPolicyMap = - ImmutableMap<StringPiece, OverlayableItem::Policy>::CreatePreSorted({ - {"odm", OverlayableItem::Policy::kOdm}, - {"oem", OverlayableItem::Policy::kOem}, - {"product", OverlayableItem::Policy::kProduct}, - {"public", OverlayableItem::Policy::kPublic}, - {"signature", OverlayableItem::Policy::kSignature}, - {"system", OverlayableItem::Policy::kSystem}, - {"vendor", OverlayableItem::Policy::kVendor}, - }); - for (const StringPiece& part : util::Tokenize(maybe_type.value(), '|')) { StringPiece trimmed_part = util::TrimWhitespace(part); - const auto policy = kPolicyMap.find(trimmed_part); - if (policy == kPolicyMap.end()) { + const auto policy = std::find_if(kPolicyStringToFlag.begin(), + kPolicyStringToFlag.end(), + [trimmed_part](const auto& it) { + return trimmed_part == it.first; + }); + if (policy == kPolicyStringToFlag.end()) { diag_->Error(DiagMessage(element_source) << "<policy> has unsupported type '" << trimmed_part << "'"); error = true; diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 24531bc16445..9b70079a98c9 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -41,6 +41,8 @@ using ::testing::Pointee; using ::testing::SizeIs; using ::testing::StrEq; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; @@ -959,7 +961,7 @@ TEST_F(ResourceParserTest, ParseOverlayable) { OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SIGNATURE)); search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar")); ASSERT_TRUE(search_result); @@ -968,7 +970,7 @@ TEST_F(ResourceParserTest, ParseOverlayable) { result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SIGNATURE)); } TEST_F(ResourceParserTest, ParseOverlayableRequiresName) { @@ -1005,6 +1007,9 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { <policy type="oem"> <item type="string" name="buz" /> </policy> + <policy type="actor"> + <item type="string" name="actor" /> + </policy> </overlayable>)"; ASSERT_TRUE(TestParse(input)); @@ -1014,7 +1019,7 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION)); search_result = table_.FindResource(test::ParseNameOrDie("string/fiz")); ASSERT_TRUE(search_result); @@ -1022,7 +1027,7 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SYSTEM_PARTITION)); search_result = table_.FindResource(test::ParseNameOrDie("string/fuz")); ASSERT_TRUE(search_result); @@ -1030,7 +1035,7 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::VENDOR_PARTITION)); search_result = table_.FindResource(test::ParseNameOrDie("string/faz")); ASSERT_TRUE(search_result); @@ -1038,7 +1043,7 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PUBLIC)); search_result = table_.FindResource(test::ParseNameOrDie("string/foz")); ASSERT_TRUE(search_result); @@ -1046,7 +1051,7 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::SIGNATURE)); search_result = table_.FindResource(test::ParseNameOrDie("string/biz")); ASSERT_TRUE(search_result); @@ -1054,7 +1059,7 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kOdm)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::ODM_PARTITION)); search_result = table_.FindResource(test::ParseNameOrDie("string/buz")); ASSERT_TRUE(search_result); @@ -1062,7 +1067,15 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kOem)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::OEM_PARTITION)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/actor")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable_item = search_result.value().entry->overlayable_item.value(); + EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::ACTOR_SIGNATURE)); } TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) { @@ -1125,8 +1138,8 @@ TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor - | OverlayableItem::Policy::kPublic)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::VENDOR_PARTITION + | PolicyFlags::PUBLIC)); search_result = table_.FindResource(test::ParseNameOrDie("string/bar")); ASSERT_TRUE(search_result); @@ -1134,8 +1147,8 @@ TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) { ASSERT_TRUE(search_result.value().entry->overlayable_item); result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kSystem)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION + | PolicyFlags::SYSTEM_PARTITION)); } TEST_F(ResourceParserTest, DuplicateOverlayableIsError) { diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index 30ba1aed25f8..93a7a314d6ba 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -36,6 +36,8 @@ #include <unordered_map> #include <vector> +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { // The Public status of a resource. @@ -75,36 +77,8 @@ struct Overlayable { struct OverlayableItem { explicit OverlayableItem(const std::shared_ptr<Overlayable>& overlayable) : overlayable(overlayable) {} - - // Represents the types overlays that are allowed to overlay the resource. - typedef uint32_t PolicyFlags; - enum Policy : uint32_t { - kNone = 0x00000000, - - // The resource can be overlaid by any overlay. - kPublic = 0x00000001, - - // The resource can be overlaid by any overlay on the system partition. - kSystem = 0x00000002, - - // The resource can be overlaid by any overlay on the vendor partition. - kVendor = 0x00000004, - - // The resource can be overlaid by any overlay on the product partition. - kProduct = 0x00000008, - - // The resource can be overlaid by any overlay signed with the same signature as its actor. - kSignature = 0x00000010, - - // The resource can be overlaid by any overlay on the odm partition. - kOdm = 0x00000020, - - // The resource can be overlaid by any overlay on the oem partition. - kOem = 0x00000040, - }; - std::shared_ptr<Overlayable> overlayable; - PolicyFlags policies = Policy::kNone; + PolicyFlags policies = PolicyFlags::NONE; std::string comment; Source source; }; diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp index b97dc6b205ca..9271a7e6bae1 100644 --- a/tools/aapt2/ResourceTable_test.cpp +++ b/tools/aapt2/ResourceTable_test.cpp @@ -30,6 +30,8 @@ using ::testing::Eq; using ::testing::NotNull; using ::testing::StrEq; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { TEST(ResourceTableTest, FailToAddResourceWithBadName) { @@ -247,8 +249,8 @@ TEST(ResourceTableTest, SetOverlayable) { auto overlayable = std::make_shared<Overlayable>("Name", "overlay://theme", Source("res/values/overlayable.xml", 40)); OverlayableItem overlayable_item(overlayable); - overlayable_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_item.policies |= OverlayableItem::Policy::kVendor; + overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION; overlayable_item.comment = "comment"; overlayable_item.source = Source("res/values/overlayable.xml", 42); @@ -264,8 +266,8 @@ TEST(ResourceTableTest, SetOverlayable) { EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme")); EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kVendor)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION + | PolicyFlags::VENDOR_PARTITION)); ASSERT_THAT(result_overlayable_item.comment, StrEq("comment")); EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.source.line, 42); @@ -277,17 +279,17 @@ TEST(ResourceTableTest, SetMultipleOverlayableResources) { const ResourceName foo = test::ParseNameOrDie("android:string/foo"); auto group = std::make_shared<Overlayable>("Name", "overlay://theme"); OverlayableItem overlayable(group); - overlayable.policies = OverlayableItem::Policy::kProduct; + overlayable.policies = PolicyFlags::PRODUCT_PARTITION; ASSERT_TRUE(table.SetOverlayable(foo, overlayable, test::GetDiagnostics())); const ResourceName bar = test::ParseNameOrDie("android:string/bar"); OverlayableItem overlayable2(group); - overlayable2.policies = OverlayableItem::Policy::kProduct; + overlayable2.policies = PolicyFlags::PRODUCT_PARTITION; ASSERT_TRUE(table.SetOverlayable(bar, overlayable2, test::GetDiagnostics())); const ResourceName baz = test::ParseNameOrDie("android:string/baz"); OverlayableItem overlayable3(group); - overlayable3.policies = OverlayableItem::Policy::kVendor; + overlayable3.policies = PolicyFlags::VENDOR_PARTITION; ASSERT_TRUE(table.SetOverlayable(baz, overlayable3, test::GetDiagnostics())); } @@ -296,12 +298,12 @@ TEST(ResourceTableTest, SetOverlayableDifferentResourcesDifferentName) { const ResourceName foo = test::ParseNameOrDie("android:string/foo"); OverlayableItem overlayable_item(std::make_shared<Overlayable>("Name", "overlay://theme")); - overlayable_item.policies = OverlayableItem::Policy::kProduct; + overlayable_item.policies = PolicyFlags::PRODUCT_PARTITION; ASSERT_TRUE(table.SetOverlayable(foo, overlayable_item, test::GetDiagnostics())); const ResourceName bar = test::ParseNameOrDie("android:string/bar"); OverlayableItem overlayable_item2(std::make_shared<Overlayable>("Name2", "overlay://theme")); - overlayable_item2.policies = OverlayableItem::Policy::kProduct; + overlayable_item2.policies = PolicyFlags::PRODUCT_PARTITION; ASSERT_TRUE(table.SetOverlayable(bar, overlayable_item2, test::GetDiagnostics())); } diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index 8a2f5afa7255..ab9ce66b0ae3 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -167,6 +167,7 @@ message OverlayableItem { SIGNATURE = 5; ODM = 6; OEM = 7; + ACTOR = 8; } // The location of the <item> declaration in source. diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index 5b6935bafe71..bf886c2f893f 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -1766,9 +1766,12 @@ class Linker { return 1; } - // First extract the Package name without modifying it (via --rename-manifest-package). - if (Maybe<AppInfo> maybe_app_info = + // Determine the package name under which to merge resources. + if (options_.rename_resources_package) { + context_->SetCompilationPackage(options_.rename_resources_package.value()); + } else if (Maybe<AppInfo> maybe_app_info = ExtractAppInfoFromManifest(manifest_xml.get(), context_->GetDiagnostics())) { + // Extract the package name from the manifest ignoring the value of --rename-manifest-package. const AppInfo& app_info = maybe_app_info.value(); context_->SetCompilationPackage(app_info.package); } diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 4722358be8f7..e7be43459e16 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -45,6 +45,7 @@ struct LinkOptions { bool auto_add_overlay = false; bool override_styles_instead_of_overlaying = false; OutputFormat output_format = OutputFormat::kApk; + Maybe<std::string> rename_resources_package; // Java/Proguard options. Maybe<std::string> generate_java_class_path; @@ -256,6 +257,8 @@ class LinkCommand : public Command { &options_.override_styles_instead_of_overlaying); AddOptionalFlag("--rename-manifest-package", "Renames the package in AndroidManifest.xml.", &options_.manifest_fixer_options.rename_manifest_package); + AddOptionalFlag("--rename-resources-package", "Renames the package in resources table", + &options_.rename_resources_package); AddOptionalFlag("--rename-instrumentation-target-package", "Changes the name of the target package for instrumentation. Most useful\n" "when used in conjunction with --rename-manifest-package.", diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index fcd6aaafba7a..f362744c0942 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -455,35 +455,6 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { const ResTable_overlayable_policy_header* policy_header = ConvertTo<ResTable_overlayable_policy_header>(parser.chunk()); - OverlayableItem::PolicyFlags policies = OverlayableItem::Policy::kNone; - if (policy_header->policy_flags & ResTable_overlayable_policy_header::POLICY_PUBLIC) { - policies |= OverlayableItem::Policy::kPublic; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION) { - policies |= OverlayableItem::Policy::kSystem; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION) { - policies |= OverlayableItem::Policy::kVendor; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) { - policies |= OverlayableItem::Policy::kProduct; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_SIGNATURE) { - policies |= OverlayableItem::Policy::kSignature; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_ODM_PARTITION) { - policies |= OverlayableItem::Policy::kOdm; - } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_OEM_PARTITION) { - policies |= OverlayableItem::Policy::kOem; - } - const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>( ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize)); const ResTable_ref* const ref_end = ref_begin @@ -501,7 +472,7 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { } OverlayableItem overlayable_item(overlayable); - overlayable_item.policies = policies; + overlayable_item.policies = policy_header->policy_flags; if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) { return false; } diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index cbce8a59bae3..4784ecf3d12c 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -233,7 +233,7 @@ class MapFlattenVisitor : public ValueVisitor { struct OverlayableChunk { std::string actor; Source source; - std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids; + std::map<PolicyFlags, std::set<ResourceId>> policy_ids; }; class PackageFlattener { @@ -493,35 +493,12 @@ class PackageFlattener { return false; } - uint32_t policy_flags = 0; - if (item.policies & OverlayableItem::Policy::kPublic) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } - if (item.policies & OverlayableItem::Policy::kSystem) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kVendor) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kProduct) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kSignature) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_SIGNATURE; - } - if (item.policies & OverlayableItem::Policy::kOdm) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_ODM_PARTITION; - } - if (item.policies & OverlayableItem::Policy::kOem) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_OEM_PARTITION; - } - - auto policy = overlayable_chunk->policy_ids.find(policy_flags); + auto policy = overlayable_chunk->policy_ids.find(item.policies); if (policy != overlayable_chunk->policy_ids.end()) { policy->second.insert(id); } else { overlayable_chunk->policy_ids.insert( - std::make_pair(policy_flags, std::set<ResourceId>{id})); + std::make_pair(item.policies, std::set<ResourceId>{id})); } } } @@ -559,7 +536,8 @@ class PackageFlattener { ChunkWriter policy_writer(buffer); auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>( RES_TABLE_OVERLAYABLE_POLICY_TYPE); - policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)); + policy_type->policy_flags = + static_cast<PolicyFlags>(util::HostToDevice32(static_cast<uint32_t>(policy_ids.first))); policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>( policy_ids.second.size())); // Write the ids after the policy header diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index af2293f0f82b..59627ce579af 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -32,6 +32,8 @@ using ::testing::Gt; using ::testing::IsNull; using ::testing::NotNull; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { class TableFlattenerTest : public ::testing::Test { @@ -671,9 +673,9 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSuc TEST_F(TableFlattenerTest, FlattenOverlayable) { OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme")); - overlayable_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_item.policies |= OverlayableItem::Policy::kSystem; - overlayable_item.policies |= OverlayableItem::Policy::kVendor; + overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION; + overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION; std::string name = "com.app.test:integer/overlayable"; std::unique_ptr<ResourceTable> table = @@ -691,27 +693,27 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) { ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(result_overlayable_item.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kVendor - | OverlayableItem::Policy::kProduct); + EXPECT_EQ(result_overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::VENDOR_PARTITION + | PolicyFlags::PRODUCT_PARTITION); } TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme"); std::string name_zero = "com.app.test:integer/overlayable_zero_item"; OverlayableItem overlayable_item_zero(overlayable); - overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; - overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item_zero.policies |= PolicyFlags::SYSTEM_PARTITION; std::string name_one = "com.app.test:integer/overlayable_one_item"; OverlayableItem overlayable_item_one(overlayable); - overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= PolicyFlags::PUBLIC; std::string name_two = "com.app.test:integer/overlayable_two_item"; OverlayableItem overlayable_item_two(overlayable); - overlayable_item_two.policies |= OverlayableItem::Policy::kProduct; - overlayable_item_two.policies |= OverlayableItem::Policy::kSystem; - overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; + overlayable_item_two.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item_two.policies |= PolicyFlags::SYSTEM_PARTITION; + overlayable_item_two.policies |= PolicyFlags::VENDOR_PARTITION; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -732,47 +734,48 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct); + EXPECT_EQ(overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION); search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); + EXPECT_EQ(overlayable_item.policies, PolicyFlags::PUBLIC); search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kVendor); + EXPECT_EQ(overlayable_item.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION + | PolicyFlags::VENDOR_PARTITION); } TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { auto group = std::make_shared<Overlayable>("TestName", "overlay://theme"); std::string name_zero = "com.app.test:integer/overlayable_zero"; OverlayableItem overlayable_item_zero(group); - overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; - overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item_zero.policies |= PolicyFlags::SYSTEM_PARTITION; auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization"); std::string name_one = "com.app.test:integer/overlayable_one"; OverlayableItem overlayable_item_one(group_one); - overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= PolicyFlags::PUBLIC; std::string name_two = "com.app.test:integer/overlayable_two"; OverlayableItem overlayable_item_two(group); - overlayable_item_two.policies |= OverlayableItem::Policy::kOdm; - overlayable_item_two.policies |= OverlayableItem::Policy::kOem; - overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; + overlayable_item_two.policies |= PolicyFlags::ODM_PARTITION; + overlayable_item_two.policies |= PolicyFlags::OEM_PARTITION; + overlayable_item_two.policies |= PolicyFlags::VENDOR_PARTITION; std::string name_three = "com.app.test:integer/overlayable_three"; OverlayableItem overlayable_item_three(group_one); - overlayable_item_three.policies |= OverlayableItem::Policy::kSignature; + overlayable_item_three.policies |= PolicyFlags::SIGNATURE; + overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -796,8 +799,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION); search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); ASSERT_TRUE(search_result); @@ -806,7 +809,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::PUBLIC); search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); ASSERT_TRUE(search_result); @@ -815,9 +818,9 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kOdm - | OverlayableItem::Policy::kOem - | OverlayableItem::Policy::kVendor); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::ODM_PARTITION + | PolicyFlags::OEM_PARTITION + | PolicyFlags::VENDOR_PARTITION); search_result = output_table.FindResource(test::ParseNameOrDie(name_three)); ASSERT_TRUE(search_result); @@ -826,7 +829,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSignature); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE + | PolicyFlags::ACTOR_SIGNATURE); } TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index 4cd6e930915d..2fd01d7f3dee 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -30,6 +30,8 @@ using ::android::ConfigDescription; using ::android::LocaleValue; using ::android::ResStringPool; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { namespace { @@ -379,25 +381,28 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, for (const int policy : pb_overlayable.policy()) { switch (policy) { case pb::OverlayableItem::PUBLIC: - out_overlayable->policies |= OverlayableItem::Policy::kPublic; + out_overlayable->policies |= PolicyFlags::PUBLIC; break; case pb::OverlayableItem::SYSTEM: - out_overlayable->policies |= OverlayableItem::Policy::kSystem; + out_overlayable->policies |= PolicyFlags::SYSTEM_PARTITION; break; case pb::OverlayableItem::VENDOR: - out_overlayable->policies |= OverlayableItem::Policy::kVendor; + out_overlayable->policies |= PolicyFlags::VENDOR_PARTITION; break; case pb::OverlayableItem::PRODUCT: - out_overlayable->policies |= OverlayableItem::Policy::kProduct; + out_overlayable->policies |= PolicyFlags::PRODUCT_PARTITION; break; case pb::OverlayableItem::SIGNATURE: - out_overlayable->policies |= OverlayableItem::Policy::kSignature; + out_overlayable->policies |= PolicyFlags::SIGNATURE; break; case pb::OverlayableItem::ODM: - out_overlayable->policies |= OverlayableItem::Policy::kOdm; + out_overlayable->policies |= PolicyFlags::ODM_PARTITION; break; case pb::OverlayableItem::OEM: - out_overlayable->policies |= OverlayableItem::Policy::kOem; + out_overlayable->policies |= PolicyFlags::OEM_PARTITION; + break; + case pb::OverlayableItem::ACTOR: + out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE; break; default: *out_error = "unknown overlayable policy"; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index d9f6c193fc2f..ba6df22af9d3 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -21,6 +21,8 @@ using android::ConfigDescription; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { void SerializeStringPoolToPb(const StringPool& pool, pb::StringPool* out_pb_pool, IDiagnostics* diag) { @@ -299,27 +301,30 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item pb::OverlayableItem* pb_overlayable_item = pb_entry->mutable_overlayable_item(); pb_overlayable_item->set_overlayable_idx(i); - if (overlayable_item.policies & OverlayableItem::Policy::kPublic) { + if (overlayable_item.policies & PolicyFlags::PUBLIC) { pb_overlayable_item->add_policy(pb::OverlayableItem::PUBLIC); } - if (overlayable_item.policies & OverlayableItem::Policy::kProduct) { + if (overlayable_item.policies & PolicyFlags::PRODUCT_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT); } - if (overlayable_item.policies & OverlayableItem::Policy::kSystem) { + if (overlayable_item.policies & PolicyFlags::SYSTEM_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM); } - if (overlayable_item.policies & OverlayableItem::Policy::kVendor) { + if (overlayable_item.policies & PolicyFlags::VENDOR_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR); } - if (overlayable_item.policies & OverlayableItem::Policy::kSignature) { + if (overlayable_item.policies & PolicyFlags::SIGNATURE) { pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE); } - if (overlayable_item.policies & OverlayableItem::Policy::kOdm) { + if (overlayable_item.policies & PolicyFlags::ODM_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::ODM); } - if (overlayable_item.policies & OverlayableItem::Policy::kOem) { + if (overlayable_item.policies & PolicyFlags::OEM_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::OEM); } + if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) { + pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR); + } if (source_pool != nullptr) { SerializeSourceToPb(overlayable_item.source, source_pool, diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index 61a8335e17a7..1a7de6dc1c48 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -28,6 +28,8 @@ using ::testing::NotNull; using ::testing::SizeIs; using ::testing::StrEq; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { class MockFileCollection : public io::IFileCollection { @@ -171,7 +173,7 @@ TEST(ProtoSerializeTest, SerializeSinglePackage) { EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme")); EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.overlayable->source.line, Eq(40)); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::NONE)); EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.source.line, Eq(42)); } @@ -516,23 +518,28 @@ TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) { TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { OverlayableItem overlayable_item_foo(std::make_shared<Overlayable>( "CustomizableResources", "overlay://customization")); - overlayable_item_foo.policies |= OverlayableItem::Policy::kSystem; - overlayable_item_foo.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_foo.policies |= PolicyFlags::SYSTEM_PARTITION; + overlayable_item_foo.policies |= PolicyFlags::PRODUCT_PARTITION; OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>( "TaskBar", "overlay://theme")); - overlayable_item_bar.policies |= OverlayableItem::Policy::kPublic; - overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor; + overlayable_item_bar.policies |= PolicyFlags::PUBLIC; + overlayable_item_bar.policies |= PolicyFlags::VENDOR_PARTITION; OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>( "FontPack", "overlay://theme")); - overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_baz.policies |= PolicyFlags::PUBLIC; OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>( "IconPack", "overlay://theme")); - overlayable_item_boz.policies |= OverlayableItem::Policy::kSignature; - overlayable_item_boz.policies |= OverlayableItem::Policy::kOdm; - overlayable_item_boz.policies |= OverlayableItem::Policy::kOem; + overlayable_item_boz.policies |= PolicyFlags::SIGNATURE; + overlayable_item_boz.policies |= PolicyFlags::ODM_PARTITION; + overlayable_item_boz.policies |= PolicyFlags::OEM_PARTITION; + + OverlayableItem overlayable_item_actor_config(std::make_shared<Overlayable>( + "ActorConfig", "overlay://theme")); + overlayable_item_actor_config.policies |= PolicyFlags::SIGNATURE; + overlayable_item_actor_config.policies |= PolicyFlags::ACTOR_SIGNATURE; OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>( "Other", "overlay://customization")); @@ -546,6 +553,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz) .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz) .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz) + .SetOverlayable("com.app.a:bool/actor_config", overlayable_item_actor_config) .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true")) .Build(); @@ -565,8 +573,8 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("CustomizableResources")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://customization")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SYSTEM_PARTITION + | PolicyFlags::PRODUCT_PARTITION)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar")); ASSERT_TRUE(search_result); @@ -574,8 +582,8 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic - | OverlayableItem::Policy::kVendor)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC + | PolicyFlags::VENDOR_PARTITION)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz")); ASSERT_TRUE(search_result); @@ -583,7 +591,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("FontPack")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::PUBLIC)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz")); ASSERT_TRUE(search_result); @@ -591,16 +599,25 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature - | OverlayableItem::Policy::kOdm - | OverlayableItem::Policy::kOem)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE + | PolicyFlags::ODM_PARTITION + | PolicyFlags::OEM_PARTITION)); + + search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/actor_config")); + ASSERT_TRUE(search_result); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + overlayable_item = search_result.value().entry->overlayable_item.value(); + EXPECT_THAT(overlayable_item.overlayable->name, Eq("ActorConfig")); + EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE + | PolicyFlags::ACTOR_SIGNATURE)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz")); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("Other")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kNone)); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::NONE)); EXPECT_THAT(overlayable_item.comment, Eq("comment")); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz")); diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp index 0be4ccf9ae85..69cf5ee7002b 100644 --- a/tools/aapt2/link/TableMerger_test.cpp +++ b/tools/aapt2/link/TableMerger_test.cpp @@ -29,6 +29,8 @@ using ::testing::Pointee; using ::testing::StrEq; using ::testing::UnorderedElementsAreArray; +using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; + namespace aapt { struct TableMergerTest : public ::testing::Test { @@ -487,8 +489,8 @@ TEST_F(TableMergerTest, SetOverlayable) { auto overlayable = std::make_shared<Overlayable>("CustomizableResources", "overlay://customization"); OverlayableItem overlayable_item(overlayable); - overlayable_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_item.policies |= OverlayableItem::Policy::kVendor; + overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION; + overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION; std::unique_ptr<ResourceTable> table_a = test::ResourceTableBuilder() @@ -516,8 +518,8 @@ TEST_F(TableMergerTest, SetOverlayable) { OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources")); EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kVendor)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PRODUCT_PARTITION + | PolicyFlags::VENDOR_PARTITION)); } TEST_F(TableMergerTest, SetOverlayableLater) { @@ -530,8 +532,8 @@ TEST_F(TableMergerTest, SetOverlayableLater) { .Build(); OverlayableItem overlayable_item(overlayable); - overlayable_item.policies |= OverlayableItem::Policy::kPublic; - overlayable_item.policies |= OverlayableItem::Policy::kSystem; + overlayable_item.policies |= PolicyFlags::PUBLIC; + overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION; std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -552,15 +554,15 @@ TEST_F(TableMergerTest, SetOverlayableLater) { OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources")); EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic - | OverlayableItem::Policy::kSystem)); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::PUBLIC + | PolicyFlags::SYSTEM_PARTITION)); } TEST_F(TableMergerTest, SameResourceDifferentNameFail) { auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", "overlay://customization"); OverlayableItem overlayable_item_first(overlayable_first); - overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION; std::unique_ptr<ResourceTable> table_a = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -570,7 +572,7 @@ TEST_F(TableMergerTest, SameResourceDifferentNameFail) { auto overlayable_second = std::make_shared<Overlayable>("ThemeResources", "overlay://customization"); OverlayableItem overlayable_item_second(overlayable_second); - overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION; std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -589,7 +591,7 @@ TEST_F(TableMergerTest, SameResourceDifferentActorFail) { auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", "overlay://customization"); OverlayableItem overlayable_item_first(overlayable_first); - overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION; std::unique_ptr<ResourceTable> table_a = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -599,7 +601,7 @@ TEST_F(TableMergerTest, SameResourceDifferentActorFail) { auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources", "overlay://theme"); OverlayableItem overlayable_item_second(overlayable_second); - overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION; std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -618,7 +620,7 @@ TEST_F(TableMergerTest, SameResourceDifferentPoliciesFail) { auto overlayable_first = std::make_shared<Overlayable>("CustomizableResources", "overlay://customization"); OverlayableItem overlayable_item_first(overlayable_first); - overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION; std::unique_ptr<ResourceTable> table_a = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -628,7 +630,7 @@ TEST_F(TableMergerTest, SameResourceDifferentPoliciesFail) { auto overlayable_second = std::make_shared<Overlayable>("CustomizableResources", "overlay://customization"); OverlayableItem overlayable_item_second(overlayable_second); - overlayable_item_second.policies |= OverlayableItem::Policy::kSignature; + overlayable_item_second.policies |= PolicyFlags::SIGNATURE; std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -648,7 +650,7 @@ TEST_F(TableMergerTest, SameResourceSameOverlayable) { "overlay://customization"); OverlayableItem overlayable_item_first(overlayable); - overlayable_item_first.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_first.policies |= PolicyFlags::PRODUCT_PARTITION; std::unique_ptr<ResourceTable> table_a = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -656,7 +658,7 @@ TEST_F(TableMergerTest, SameResourceSameOverlayable) { .Build(); OverlayableItem overlayable_item_second(overlayable); - overlayable_item_second.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_second.policies |= PolicyFlags::PRODUCT_PARTITION; std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp index d5031d7d4628..843e82023afe 100644 --- a/tools/stats_log_api_gen/Android.bp +++ b/tools/stats_log_api_gen/Android.bp @@ -121,7 +121,6 @@ cc_library { shared_libs: [ "liblog", "libcutils", - "libstatssocket", ], apex_available: [ "//apex_available:platform", @@ -129,5 +128,13 @@ cc_library { "com.android.os.statsd", "test_com.android.os.statsd", ], + target: { + android: { + shared_libs: ["libstatssocket"], + }, + host: { + static_libs: ["libstatssocket"], + }, + }, } diff --git a/wifi/Android.bp b/wifi/Android.bp index e253d6d4f6cb..91174d3c3be2 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -47,7 +47,7 @@ filegroup { // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache // to a separate package. "java/android/net/wifi/WifiNetworkScoreCache.java", - "java/android/net/wifi/WifiOemMigrationHook.java", + "java/android/net/wifi/WifiMigration.java", "java/android/net/wifi/nl80211/*.java", ":libwificond_ipc_aidl", ], diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/wifi/java/android/net/wifi/IScoreChangeCallback.aidl index 462a97844d76..d691f41b2858 100644 --- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl +++ b/wifi/java/android/net/wifi/IScoreChangeCallback.aidl @@ -16,16 +16,14 @@ package android.net.wifi; -import android.net.NetworkScore; - /** - * Interface for Wi-Fi network score callback. + * Interface for Wi-Fi score callback. * * @hide */ oneway interface IScoreChangeCallback { - void onScoreChange(int sessionId, in NetworkScore score); + void onScoreChange(int sessionId, int score); void onTriggerUpdateOfWifiUsabilityStats(int sessionId); } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 3025caf74000..30a76e463f67 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -97,7 +97,7 @@ interface IWifiManager void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable); - void setMeteredOverridePasspoint(String fqdn, int meteredOverride); + void setPasspointMeteredOverride(String fqdn, int meteredOverride); boolean startScan(String packageName, String featureId); diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 51927af17888..9256c57ab4b9 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -24,8 +24,6 @@ import android.compat.annotation.UnsupportedAppUsage; 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.nio.ByteBuffer; @@ -861,19 +859,7 @@ public class ScanResult implements Parcelable { } } - /** - * Construct an empty scan result. - * - * Test code has a need to construct a ScanResult in a specific state. - * (Note that mocking using Mockito does not work if the object needs to be parceled and - * unparceled.) - * Export a @SystemApi default constructor to allow tests to construct an empty ScanResult - * object. The test can then directly set the fields it cares about. - * - * @hide - */ - @SystemApi - @VisibleForTesting + /** Construct an empty scan result. */ public ScanResult() { } diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index c48e89526ae0..0229b846bc6d 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -1713,7 +1713,7 @@ public class WifiConfiguration implements Parcelable { * @return network disable reason string, or null if the reason is invalid. */ @Nullable - public static String getNetworkDisableReasonString( + public static String getNetworkSelectionDisableReasonString( @NetworkSelectionDisableReason int reason) { DisableReasonInfo info = DISABLE_REASON_INFOS.get(reason); if (info == null) { @@ -1727,8 +1727,8 @@ public class WifiConfiguration implements Parcelable { * @return current network disable reason in String (for debug purpose) * @hide */ - public String getNetworkDisableReasonString() { - return getNetworkDisableReasonString(mNetworkSelectionDisableReason); + public String getNetworkSelectionDisableReasonString() { + return getNetworkSelectionDisableReasonString(mNetworkSelectionDisableReason); } /** @@ -2189,17 +2189,21 @@ public class WifiConfiguration implements Parcelable { sbuf.append(" NetworkSelectionStatus ") - .append(mNetworkSelectionStatus.getNetworkStatusString() + "\n"); + .append(mNetworkSelectionStatus.getNetworkStatusString()) + .append("\n"); if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) { sbuf.append(" mNetworkSelectionDisableReason ") - .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n"); + .append(mNetworkSelectionStatus.getNetworkSelectionDisableReasonString()) + .append("\n"); for (int index = NetworkSelectionStatus.DISABLED_NONE; index < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) { if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) { - sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index) - + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index) - + "\n"); + sbuf.append( + NetworkSelectionStatus.getNetworkSelectionDisableReasonString(index)) + .append(" counter:") + .append(mNetworkSelectionStatus.getDisableReasonCounter(index)) + .append("\n"); } } } diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 0c306b4fb8cc..142854a9e41b 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -28,8 +28,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import com.android.internal.annotations.VisibleForTesting; - import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; @@ -380,20 +378,7 @@ public class WifiInfo implements Parcelable { } } - /** - * WifiInfo exports an immutable public API. - * However, test code has a need to construct a WifiInfo in a specific state. - * (Note that mocking using Mockito does not work if the object needs to be parceled and - * unparceled.) - * Export a @SystemApi Builder to allow tests to construct a WifiInfo object - * in the desired state, without sacrificing WifiInfo's immutability. - * - * @hide - */ - // This builder was not made public to reduce confusion for external developers as there are - // no legitimate uses for this builder except for testing. - @SystemApi - @VisibleForTesting + /** Builder for WifiInfo */ public static final class Builder { private final WifiInfo mWifiInfo = new WifiInfo(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index b1a4cac5864a..6487e8390374 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -39,7 +39,6 @@ import android.net.ConnectivityManager; import android.net.DhcpInfo; import android.net.MacAddress; import android.net.Network; -import android.net.NetworkScore; import android.net.NetworkStack; import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; @@ -1881,9 +1880,11 @@ public class WifiManager { * NOTE: * <li> These networks are just a suggestion to the platform. The platform will ultimately * decide on which network the device connects to. </li> - * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is - * currently connected to a suggested network which is being removed then the device will - * disconnect from that network.</li> + * <li> When an app is uninstalled or disabled, all its suggested networks are discarded. + * If the device is currently connected to a suggested network which is being removed then the + * device will disconnect from that network.</li> + * <li> If user reset network settings, all added suggestions will be discarded. Apps can use + * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li> * <li> In-place modification of existing suggestions are allowed. * If the provided suggestions {@link WifiNetworkSuggestion#equals(Object)} any previously * provided suggestions by the app. Previous suggestions will be updated</li> @@ -4429,9 +4430,9 @@ public class WifiManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void setMeteredOverridePasspoint(@NonNull String fqdn, int meteredOverride) { + public void setPasspointMeteredOverride(@NonNull String fqdn, int meteredOverride) { try { - mService.setMeteredOverridePasspoint(fqdn, meteredOverride); + mService.setPasspointMeteredOverride(fqdn, meteredOverride); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -5994,11 +5995,10 @@ public class WifiManager { * * @param sessionId The ID to indicate current Wi-Fi network connection obtained from * {@link WifiConnectedNetworkScorer#start(int)}. - * @param score The {@link android.net.NetworkScore} object representing the - * characteristics of current Wi-Fi network. Populated by connected network - * scorer in applications. + * @param score The score representing link quality of current Wi-Fi network connection. + * Populated by connected network scorer in applications.. */ - void onScoreChange(int sessionId, @NonNull NetworkScore score); + void onScoreChange(int sessionId, int score); /** * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}. @@ -6024,7 +6024,7 @@ public class WifiManager { } @Override - public void onScoreChange(int sessionId, @NonNull NetworkScore score) { + public void onScoreChange(int sessionId, int score) { try { mScoreChangeCallback.onScoreChange(sessionId, score); } catch (RemoteException e) { diff --git a/wifi/java/android/net/wifi/WifiOemMigrationHook.java b/wifi/java/android/net/wifi/WifiMigration.java index 5301dd013363..a3482d732a1b 100755 --- a/wifi/java/android/net/wifi/WifiOemMigrationHook.java +++ b/wifi/java/android/net/wifi/WifiMigration.java @@ -34,9 +34,9 @@ import java.util.List; * @hide */ @SystemApi -public final class WifiOemMigrationHook { +public final class WifiMigration { - private WifiOemMigrationHook() { } + private WifiMigration() { } /** * Container for all the wifi config data to migrate. @@ -161,16 +161,16 @@ public final class WifiOemMigrationHook { * Load data from OEM's config store. * <p> * Note: - * <li> OEM's need to implement {@link #loadFromConfigStore()} ()} only if their - * existing config store format or file locations differs from the vanilla AOSP implementation ( - * which is what the wifi mainline module understands). + * <li>OEMs need to implement {@link #loadFromConfigStore()} ()} only if their + * existing config store format or file locations differs from the vanilla AOSP implementation. * </li> - * <li> The wifi mainline module will invoke {@link #loadFromConfigStore()} method on every + * <li>The wifi mainline module will invoke {@link #loadFromConfigStore()} method on every * bootup, its the responsibility of the OEM implementation to ensure that this method returns * non-null data only on the first bootup. Once the migration is done, the OEM can safely delete - * their config store files and then return null on any subsequent reboots. The first & only - * relevant invocation of {@link #loadFromConfigStore()} occurs when a previously released - * device upgrades to the wifi mainline module from an OEM implementation of the wifi stack. + * their config store files when {@link #removeConfigStore()} is invoked. + * <li>The first & only relevant invocation of {@link #loadFromConfigStore()} occurs when a + * previously released device upgrades to the wifi mainline module from an OEM implementation + * of the wifi stack. * </li> * * @return Instance of {@link ConfigStoreMigrationData} for migrating data, null if no @@ -178,11 +178,27 @@ public final class WifiOemMigrationHook { */ @Nullable public static ConfigStoreMigrationData loadFromConfigStore() { - // Note: OEM's should add code to parse data from their config store format here! + // Note: OEMs should add code to parse data from their config store format here! return null; } /** + * Remove OEM's config store. + * <p> + * Note: + * <li>OEMs need to implement {@link #removeConfigStore()} only if their + * existing config store format or file locations differs from the vanilla AOSP implementation ( + * which is what the wifi mainline module understands). + * </li> + * <li> The wifi mainline module will invoke {@link #removeConfigStore()} after it migrates + * all the existing data retrieved from {@link #loadFromConfigStore()}. + * </li> + */ + public static void removeConfigStore() { + // Note: OEMs should remove their custom config store files here! + } + + /** * Container for all the wifi settings data to migrate. */ public static final class SettingsMigrationData implements Parcelable { diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index a854a4ba3ae5..6dbb0bd757d8 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -753,7 +753,7 @@ public final class WifiNetworkSuggestion implements Parcelable { boolean isUserInteractionRequired, boolean isUserAllowedToManuallyConnect, boolean isInitialAutoJoinEnabled, - boolean isNetworkUntrusted) { + boolean isNetworkUntrusted) { checkNotNull(networkConfiguration); this.wifiConfiguration = networkConfiguration; this.passpointConfiguration = passpointConfiguration; @@ -858,13 +858,106 @@ public final class WifiNetworkSuggestion implements Parcelable { } /** + * Get the BSSID, or null if unset. + * @see Builder#setBssid(MacAddress) + */ + @Nullable + public MacAddress getBssid() { + if (wifiConfiguration.BSSID == null) { + return null; + } + return MacAddress.fromString(wifiConfiguration.BSSID); + } + + /** @see Builder#setCredentialSharedWithUser(boolean) */ + public boolean isCredentialSharedWithUser() { + return isUserAllowedToManuallyConnect; + } + + /** @see Builder#setIsAppInteractionRequired(boolean) */ + public boolean isAppInteractionRequired() { + return isAppInteractionRequired; + } + + /** @see Builder#setIsEnhancedOpen(boolean) */ + public boolean isEnhancedOpen() { + return wifiConfiguration.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE); + } + + /** @see Builder#setIsHiddenSsid(boolean) */ + public boolean isHiddenSsid() { + return wifiConfiguration.hiddenSSID; + } + + /** @see Builder#setIsInitialAutojoinEnabled(boolean) */ + public boolean isInitialAutojoinEnabled() { + return isInitialAutoJoinEnabled; + } + + /** @see Builder#setIsMetered(boolean) */ + public boolean isMetered() { + return wifiConfiguration.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED; + } + + /** @see Builder#setIsUserInteractionRequired(boolean) */ + public boolean isUserInteractionRequired() { + return isUserInteractionRequired; + } + + /** * Get the {@link PasspointConfiguration} associated with this Suggestion, or null if this * Suggestion is not for a Passpoint network. - * @hide */ - @SystemApi @Nullable - public PasspointConfiguration getPasspointConfiguration() { + public PasspointConfiguration getPasspointConfig() { return passpointConfiguration; } + + /** @see Builder#setPriority(int) */ + @IntRange(from = 0) + public int getPriority() { + return wifiConfiguration.priority; + } + + /** + * Return the SSID of the network, or null if this is a Passpoint network. + * @see Builder#setSsid(String) + */ + @Nullable + public String getSsid() { + if (wifiConfiguration.SSID == null) { + return null; + } + return WifiInfo.sanitizeSsid(wifiConfiguration.SSID); + } + + /** @see Builder#setUntrusted(boolean) */ + public boolean isUntrusted() { + return isNetworkUntrusted; + } + + /** + * Get the WifiEnterpriseConfig, or null if unset. + * @see Builder#setWapiEnterpriseConfig(WifiEnterpriseConfig) + * @see Builder#setWpa2EnterpriseConfig(WifiEnterpriseConfig) + * @see Builder#setWpa3EnterpriseConfig(WifiEnterpriseConfig) + */ + @Nullable + public WifiEnterpriseConfig getEnterpriseConfig() { + return wifiConfiguration.enterpriseConfig; + } + + /** + * Get the passphrase, or null if unset. + * @see Builder#setWapiPassphrase(String) + * @see Builder#setWpa2Passphrase(String) + * @see Builder#setWpa3Passphrase(String) + */ + @Nullable + public String getPassphrase() { + if (wifiConfiguration.preSharedKey == null) { + return null; + } + return WifiInfo.removeDoubleQuotes(wifiConfiguration.preSharedKey); + } } diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java index 4507cc2707d4..d1d1780a25fd 100644 --- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java @@ -722,7 +722,7 @@ public final class PasspointConfiguration implements Parcelable { if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) { return false; } - return validateForCommonR1andR2(true); + return validateForCommonR1andR2(); } /** @@ -741,17 +741,17 @@ public final class PasspointConfiguration implements Parcelable { if (mSubscriptionUpdate == null || !mSubscriptionUpdate.validate()) { return false; } - return validateForCommonR1andR2(false); + return validateForCommonR1andR2(); } - private boolean validateForCommonR1andR2(boolean isR1) { + private boolean validateForCommonR1andR2() { // Required: PerProviderSubscription/<X+>/HomeSP if (mHomeSp == null || !mHomeSp.validate()) { return false; } // Required: PerProviderSubscription/<X+>/Credential - if (mCredential == null || !mCredential.validate(isR1)) { + if (mCredential == null || !mCredential.validate()) { return false; } diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java index 9c01d3643c19..65e8b3d9283d 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java @@ -1081,11 +1081,10 @@ public final class Credential implements Parcelable { /** * Validate the configuration data. * - * @param isR1 {@code true} if the configuration is for R1 * @return true on success or false on failure * @hide */ - public boolean validate(boolean isR1) { + public boolean validate() { if (TextUtils.isEmpty(mRealm)) { Log.d(TAG, "Missing realm"); return false; @@ -1098,11 +1097,11 @@ public final class Credential implements Parcelable { // Verify the credential. if (mUserCredential != null) { - if (!verifyUserCredential(isR1)) { + if (!verifyUserCredential()) { return false; } } else if (mCertCredential != null) { - if (!verifyCertCredential(isR1)) { + if (!verifyCertCredential()) { return false; } } else if (mSimCredential != null) { @@ -1143,11 +1142,11 @@ public final class Credential implements Parcelable { /** * Verify user credential. + * If no CA certificate is provided, then the system uses the CAs in the trust store. * - * @param isR1 {@code true} if credential is for R1 * @return true if user credential is valid, false otherwise. */ - private boolean verifyUserCredential(boolean isR1) { + private boolean verifyUserCredential() { if (mUserCredential == null) { Log.d(TAG, "Missing user credential"); return false; @@ -1160,24 +1159,17 @@ public final class Credential implements Parcelable { return false; } - // CA certificate is required for R1 Passpoint profile. - // For R2, it is downloaded using cert URL provided in PPS MO after validation completes. - if (isR1 && mCaCertificates == null) { - Log.d(TAG, "Missing CA Certificate for user credential"); - return false; - } - return true; } /** * Verify certificate credential, which is used for EAP-TLS. This will verify * that the necessary client key and certificates are provided. + * If no CA certificate is provided, then the system uses the CAs in the trust store. * - * @param isR1 {@code true} if credential is for R1 * @return true if certificate credential is valid, false otherwise. */ - private boolean verifyCertCredential(boolean isR1) { + private boolean verifyCertCredential() { if (mCertCredential == null) { Log.d(TAG, "Missing certificate credential"); return false; @@ -1191,13 +1183,6 @@ public final class Credential implements Parcelable { return false; } - // Verify required key and certificates for certificate credential. - // CA certificate is required for R1 Passpoint profile. - // For R2, it is downloaded using cert URL provided in PPS MO after validation completes. - if (isR1 && mCaCertificates == null) { - Log.d(TAG, "Missing CA Certificate for certificate credential"); - return false; - } if (mClientPrivateKey == null) { Log.d(TAG, "Missing client private key for certificate credential"); return false; diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 234d929fc05a..76ac8373374a 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -1803,10 +1803,10 @@ public class WifiManagerTest { * {@link WifiManager#setMacRandomizationSettingPasspointEnabled(String, boolean)} */ @Test - public void testSetMeteredOverridePasspoint() throws Exception { + public void testSetPasspointMeteredOverride() throws Exception { final String fqdn = "FullyQualifiedDomainName"; - mWifiManager.setMeteredOverridePasspoint(fqdn, METERED_OVERRIDE_METERED); - verify(mWifiService).setMeteredOverridePasspoint(fqdn, METERED_OVERRIDE_METERED); + mWifiManager.setPasspointMeteredOverride(fqdn, METERED_OVERRIDE_METERED); + verify(mWifiService).setPasspointMeteredOverride(fqdn, METERED_OVERRIDE_METERED); } /** diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java index 0a3e989d18f0..c6825822f4cc 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java @@ -158,7 +158,7 @@ public class CredentialTest { } /** - * Verify parcel read/write for an user credential. + * Verify parcel read/write for a user credential. * * @throws Exception */ @@ -176,14 +176,14 @@ public class CredentialTest { Credential cred = createCredentialWithUserCredential(); // For R1 validation - assertTrue(cred.validate(true)); + assertTrue(cred.validate()); // For R2 validation - assertTrue(cred.validate(false)); + assertTrue(cred.validate()); } /** - * Verify that an user credential without CA Certificate is invalid. + * Verify that a user credential without CA Certificate is valid. * * @throws Exception */ @@ -192,15 +192,12 @@ public class CredentialTest { Credential cred = createCredentialWithUserCredential(); cred.setCaCertificate(null); - // For R1 validation - assertFalse(cred.validate(true)); - - // For R2 validation - assertTrue(cred.validate(false)); + // Accept a configuration with no CA certificate, the system will use the default cert store + assertTrue(cred.validate()); } /** - * Verify that an user credential with EAP type other than EAP-TTLS is invalid. + * Verify that a user credential with EAP type other than EAP-TTLS is invalid. * * @throws Exception */ @@ -210,15 +207,15 @@ public class CredentialTest { cred.getUserCredential().setEapType(EAPConstants.EAP_TLS); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** - * Verify that an user credential without realm is invalid. + * Verify that a user credential without realm is invalid. * * @throws Exception */ @@ -228,14 +225,14 @@ public class CredentialTest { cred.setRealm(null); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** - * Verify that an user credential without username is invalid. + * Verify that a user credential without username is invalid. * * @throws Exception */ @@ -245,14 +242,14 @@ public class CredentialTest { cred.getUserCredential().setUsername(null); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** - * Verify that an user credential without password is invalid. + * Verify that a user credential without password is invalid. * * @throws Exception */ @@ -262,14 +259,14 @@ public class CredentialTest { cred.getUserCredential().setPassword(null); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** - * Verify that an user credential without auth methoh (non-EAP inner method) is invalid. + * Verify that a user credential without auth methoh (non-EAP inner method) is invalid. * * @throws Exception */ @@ -279,10 +276,10 @@ public class CredentialTest { cred.getUserCredential().setNonEapInnerMethod(null); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** @@ -297,10 +294,10 @@ public class CredentialTest { Credential cred = createCredentialWithCertificateCredential(); // For R1 validation - assertTrue(cred.validate(true)); + assertTrue(cred.validate()); // For R2 validation - assertTrue(cred.validate(true)); + assertTrue(cred.validate()); } /** @@ -313,11 +310,8 @@ public class CredentialTest { Credential cred = createCredentialWithCertificateCredential(); cred.setCaCertificate(null); - // For R1 validation - assertFalse(cred.validate(true)); - - // For R2 validation - assertTrue(cred.validate(false)); + // Accept a configuration with no CA certificate, the system will use the default cert store + assertTrue(cred.validate()); } /** @@ -331,10 +325,10 @@ public class CredentialTest { cred.setClientCertificateChain(null); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** @@ -348,10 +342,10 @@ public class CredentialTest { cred.setClientPrivateKey(null); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** @@ -366,10 +360,10 @@ public class CredentialTest { cred.getCertCredential().setCertSha256Fingerprint(new byte[32]); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** @@ -382,10 +376,10 @@ public class CredentialTest { Credential cred = createCredentialWithSimCredential(); // For R1 validation - assertTrue(cred.validate(true)); + assertTrue(cred.validate()); // For R2 validation - assertTrue(cred.validate(false)); + assertTrue(cred.validate()); } /** @@ -399,10 +393,10 @@ public class CredentialTest { cred.getSimCredential().setEapType(EAPConstants.EAP_AKA); // For R1 validation - assertTrue(cred.validate(true)); + assertTrue(cred.validate()); // For R2 validation - assertTrue(cred.validate(false)); + assertTrue(cred.validate()); } /** @@ -416,10 +410,10 @@ public class CredentialTest { cred.getSimCredential().setEapType(EAPConstants.EAP_AKA_PRIME); // For R1 validation - assertTrue(cred.validate(true)); + assertTrue(cred.validate()); // For R2 validation - assertTrue(cred.validate(false)); + assertTrue(cred.validate()); } /** @@ -433,10 +427,10 @@ public class CredentialTest { cred.getSimCredential().setImsi(null); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** @@ -450,10 +444,10 @@ public class CredentialTest { cred.getSimCredential().setImsi("dummy"); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** @@ -467,14 +461,14 @@ public class CredentialTest { cred.getSimCredential().setEapType(EAPConstants.EAP_TLS); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** - * Verify that a credential contained both an user and a SIM credential is invalid. + * Verify that a credential contained both a user and a SIM credential is invalid. * * @throws Exception */ @@ -488,10 +482,10 @@ public class CredentialTest { cred.setSimCredential(simCredential); // For R1 validation - assertFalse(cred.validate(true)); + assertFalse(cred.validate()); // For R2 validation - assertFalse(cred.validate(false)); + assertFalse(cred.validate()); } /** |